password change debug update

This commit is contained in:
makearmy 2025-09-30 20:49:37 -04:00
parent 16ae6d9c1c
commit 064385ce42
2 changed files with 49 additions and 18 deletions

View file

@ -17,32 +17,58 @@ async function handle(req: Request) {
if (!current || !next) return bad("Missing current and/or new password"); if (!current || !next) return bad("Missing current and/or new password");
if (next.length < 8) return bad("Password must be at least 8 characters"); if (next.length < 8) return bad("Password must be at least 8 characters");
// 1) Fetch user provider; block with clear message if not local
const who = await fetch(`${API}/users/me?fields=id,provider,email`, {
headers: { Authorization: `Bearer ${bearer}`, Accept: "application/json" },
cache: "no-store",
});
const whoJson = await who.json().catch(() => ({}));
if (!who.ok) {
return NextResponse.json(
{ error: "Could not verify user", debug: whoJson?.errors?.[0]?.message || who.statusText },
{ status: who.status }
);
}
const provider = whoJson?.data?.provider ?? whoJson?.provider ?? "local";
if (provider !== "local") {
return NextResponse.json(
{ error: "Password managed by external provider", debug: `provider=${provider}` },
{ status: 400 }
);
}
// 2) Send both "old_password" and "current_password" for cross-version compatibility
const payload = { password: next, old_password: current, current_password: current };
const res = await fetch(`${API}/users/me`, { const res = await fetch(`${API}/users/me`, {
method: "PATCH", method: "PATCH",
headers: { headers: {
Authorization: `Bearer ${bearer}`, Authorization: `Bearer ${bearer}`,
"Content-Type": "application/json", "Content-Type": "application/json",
Accept: "application/json",
}, },
body: JSON.stringify({ password: next, old_password: current }), body: JSON.stringify(payload),
}); });
const j = await res.json().catch(() => ({})); const j = await res.json().catch(() => ({}));
if (!res.ok) { if (!res.ok) {
const reason = j?.errors?.[0]?.message || "Password change failed"; const reason =
const friendly = /invalid|credential|old_password|incorrect/i.test(reason) j?.errors?.[0]?.message ||
j?.error ||
(typeof j === "string" ? j : "") ||
"Password change failed";
// Only show the friendly message when it truly looks like a wrong-current-password case.
const friendly = res.status === 401 && /old_password|current_password|credential|invalid/i.test(reason)
? "Current password is incorrect" ? "Current password is incorrect"
: reason; : reason;
// Include upstream reason for debugging on the client
return NextResponse.json({ error: friendly, debug: reason }, { status: res.status }); return NextResponse.json({ error: friendly, debug: reason }, { status: res.status });
} }
return NextResponse.json({ ok: true }); return NextResponse.json({ ok: true });
} }
export async function POST(req: Request) { export async function POST(req: Request) { return handle(req); }
return handle(req); export async function PATCH(req: Request) { return handle(req); }
}
export async function PATCH(req: Request) {
return handle(req);
}

View file

@ -27,17 +27,22 @@ export default function PasswordChange() {
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify({ current, next }), body: JSON.stringify({ current, next }),
}); });
if (r.status === 401) {
// Wrong current or expired token; the route returns a friendly message for wrong current. // ⬇️ Parse JSON **then** use debug if present
const j = await r.json().catch(() => ({})); const j = await r.json().catch(() => ({} as any));
setMsg(j?.error || "Re-authentication required.");
return;
}
const j = await r.json().catch(() => ({}));
if (!r.ok) { if (!r.ok) {
setMsg(j?.error || "Password change failed"); // ⬇️ This is the "debug block" so you can see the upstream reason
setMsg(
j?.error
? j?.debug
? `${j.error} (${j.debug})`
: j.error
: "Password change failed"
);
return; return;
} }
setMsg("Password updated."); setMsg("Password updated.");
setCurrent(""); setCurrent("");
setNext(""); setNext("");