From 064385ce420b32081ccd6c726faa9acf90bbcdde Mon Sep 17 00:00:00 2001 From: makearmy Date: Tue, 30 Sep 2025 20:49:37 -0400 Subject: [PATCH] password change debug update --- app/api/account/password/route.ts | 46 +++++++++++++++++++++------ components/account/PasswordChange.tsx | 21 +++++++----- 2 files changed, 49 insertions(+), 18 deletions(-) diff --git a/app/api/account/password/route.ts b/app/api/account/password/route.ts index 68783129..474fe2a4 100644 --- a/app/api/account/password/route.ts +++ b/app/api/account/password/route.ts @@ -17,32 +17,58 @@ async function handle(req: Request) { if (!current || !next) return bad("Missing current and/or new password"); 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`, { method: "PATCH", headers: { Authorization: `Bearer ${bearer}`, "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(() => ({})); if (!res.ok) { - const reason = j?.errors?.[0]?.message || "Password change failed"; - const friendly = /invalid|credential|old_password|incorrect/i.test(reason) + const 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" : reason; - // Include upstream reason for debugging on the client + return NextResponse.json({ error: friendly, debug: reason }, { status: res.status }); } return NextResponse.json({ ok: true }); } -export async function POST(req: Request) { - return handle(req); -} -export async function PATCH(req: Request) { - return handle(req); -} +export async function POST(req: Request) { return handle(req); } +export async function PATCH(req: Request) { return handle(req); } diff --git a/components/account/PasswordChange.tsx b/components/account/PasswordChange.tsx index cc774680..ec68fa81 100644 --- a/components/account/PasswordChange.tsx +++ b/components/account/PasswordChange.tsx @@ -27,17 +27,22 @@ export default function PasswordChange() { headers: { "Content-Type": "application/json" }, body: JSON.stringify({ current, next }), }); - if (r.status === 401) { - // Wrong current or expired token; the route returns a friendly message for wrong current. - const j = await r.json().catch(() => ({})); - setMsg(j?.error || "Re-authentication required."); - return; - } - const j = await r.json().catch(() => ({})); + + // ⬇️ Parse JSON **then** use debug if present + const j = await r.json().catch(() => ({} as any)); + 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; } + setMsg("Password updated."); setCurrent(""); setNext("");