fix(frontend): revalidate layout after email/password login (#12285)

Requested by @ntindle

After logging in with email/password, the page navigates but renders a
blank/unauthenticated state (just logo + cookie banner). A manual page
refresh fixes it.

The `login` server action calls `signInWithPassword()` server-side but
doesn't call `revalidatePath()`, so Next.js serves cached RSC payloads
that don't reflect the new auth state. The OAuth callback route already
does this correctly.

**Fix:** Add `revalidatePath(next, "layout")` after successful login,
matching the OAuth callback pattern.

Closes SECRT-2059
This commit is contained in:
Otto
2026-03-04 22:25:48 +00:00
committed by GitHub
parent 0215332386
commit b342bfa3ba

View File

@@ -21,8 +21,14 @@ export function useLoginPage() {
const [showNotAllowedModal, setShowNotAllowedModal] = useState(false);
const isCloudEnv = environment.isCloud();
// Get redirect destination from 'next' query parameter
const nextUrl = searchParams.get("next");
// Get redirect destination from 'next' query parameter.
// Only allow relative paths to prevent open redirect attacks
// (e.g., /login?next=https://phishing.site).
const rawNext = searchParams.get("next");
const nextUrl =
rawNext && rawNext.startsWith("/") && !rawNext.startsWith("//")
? rawNext
: null;
useEffect(() => {
if (isLoggedIn && !isLoggingIn) {
@@ -93,8 +99,11 @@ export function useLoginPage() {
throw new Error(result.error || "Login failed");
}
// Prefer URL's next parameter, then use backend-determined route
router.replace(nextUrl || result.next || "/");
// Use full page navigation to ensure middleware processes the new auth cookies.
// router.replace() does a soft navigation where the cookie store may not
// immediately reflect cookies set by the server action, causing a blank page.
// This matches the OAuth flow which also uses window.location.href.
window.location.href = nextUrl || result.next || "/";
} catch (error) {
toast({
title: