diff --git a/app/auth/sign-in/page.tsx b/app/auth/sign-in/page.tsx index fccc1ca5..6dc3d8a2 100644 --- a/app/auth/sign-in/page.tsx +++ b/app/auth/sign-in/page.tsx @@ -1,12 +1,7 @@ // app/auth/sign-in/page.tsx -import { cookies } from "next/headers"; -import { redirect } from "next/navigation"; import SignIn from "./sign-in"; -export default async function SignInPage() { - const at = (await cookies()).get("ma_at")?.value; - if (at) redirect("/portal"); - - // Always land on /portal after sign-in - return ; +export default function SignInPage() { + // Do NOT redirect here. Always render the form. + return ; } diff --git a/app/auth/sign-in/sign-in.tsx b/app/auth/sign-in/sign-in.tsx index 7382267a..24587fe5 100644 --- a/app/auth/sign-in/sign-in.tsx +++ b/app/auth/sign-in/sign-in.tsx @@ -2,54 +2,74 @@ "use client"; import { useState, useCallback } from "react"; -import { useRouter } from "next/navigation"; +import { useRouter, useSearchParams } from "next/navigation"; type Props = { nextPath?: string }; export default function SignIn({ nextPath = "/portal" }: Props) { const router = useRouter(); + const sp = useSearchParams(); + + // Respect reauth/force flags from query + const reauth = sp.get("reauth") === "1" || sp.get("force") === "1"; + const next = sp.get("next") || nextPath; + const [identifier, setIdentifier] = useState(""); // email OR username const [password, setPassword] = useState(""); const [showPassword, setShowPassword] = useState(false); const [loading, setLoading] = useState(false); const [err, setErr] = useState(null); - const onSubmit = useCallback(async (e: React.FormEvent) => { - e.preventDefault(); - setErr(null); - setLoading(true); + const onSubmit = useCallback( + async (e: React.FormEvent) => { + e.preventDefault(); + setErr(null); + setLoading(true); - try { - const res = await fetch("/api/auth/login", { - method: "POST", - credentials: "include", - headers: { "Content-Type": "application/json", Accept: "application/json" }, - body: JSON.stringify({ identifier, password }), - }); + try { + const res = await fetch("/api/auth/login", { + method: "POST", + credentials: "include", + headers: { "Content-Type": "application/json", Accept: "application/json" }, + body: JSON.stringify({ identifier, password }), + }); - const txt = await res.text(); - let j: any = null; - try { j = txt ? JSON.parse(txt) : null; } catch {} + const txt = await res.text(); + let j: any = null; + try { j = txt ? JSON.parse(txt) : null; } catch {} - if (!res.ok) { - const message = j?.error || j?.message || `Sign-in failed (${res.status})`; - throw new Error(message); + if (!res.ok) { + const message = j?.error || j?.message || `Sign-in failed (${res.status})`; + throw new Error(message); + } + + // Success → go to intended destination (account page in reauth flow) + router.replace(next); + router.refresh(); + } catch (e: any) { + setErr(e?.message || "Unable to sign in."); + } finally { + setLoading(false); } - - // Always land on the portal in this new flow - router.replace(nextPath); - router.refresh(); - } catch (e: any) { - setErr(e?.message || "Unable to sign in."); - } finally { - setLoading(false); - } - }, [identifier, password, nextPath, router]); + }, + [identifier, password, next, router] + ); return ( + {reauth && ( + + Please sign in again + + For security, we need to confirm it’s you before accessing account settings. + + + )} + Sign In - Use your email or username with your password. + + Use your email or username with your password. + diff --git a/app/portal/account/AccountClient.tsx b/app/portal/account/AccountClient.tsx index 3b08dfc5..5364e1a8 100644 --- a/app/portal/account/AccountClient.tsx +++ b/app/portal/account/AccountClient.tsx @@ -62,7 +62,7 @@ export default function AccountClient() { For security, please sign in again before changing account details. Re-authenticate
Use your email or username with your password.
+ Use your email or username with your password. +