diff --git a/canvas/src/components/AuthGate.tsx b/canvas/src/components/AuthGate.tsx index be371429..e06eae0a 100644 --- a/canvas/src/components/AuthGate.tsx +++ b/canvas/src/components/AuthGate.tsx @@ -29,6 +29,11 @@ export function AuthGate({ children }: { children: ReactNode }) { setState({ kind: "anonymous", skipRedirect: true }); return; } + // Never gate /cp/auth/* paths — these ARE the login pages. + if (typeof window !== "undefined" && window.location.pathname.startsWith("/cp/auth/")) { + setState({ kind: "anonymous", skipRedirect: true }); + return; + } let cancelled = false; fetchSession() .then((s) => { diff --git a/canvas/src/lib/auth.ts b/canvas/src/lib/auth.ts index d16006ac..8514260d 100644 --- a/canvas/src/lib/auth.ts +++ b/canvas/src/lib/auth.ts @@ -44,6 +44,10 @@ export async function fetchSession(): Promise { */ export function redirectToLogin(screenHint: "sign-up" | "sign-in" = "sign-in"): void { if (typeof window === "undefined") return; + // Guard against infinite redirect loop: if we're already on the login + // page, don't redirect again (each redirect double-encodes return_to + // until the URL exceeds header limits → 431). + if (window.location.pathname.startsWith("/cp/auth/")) return; const returnTo = window.location.href; const path = screenHint === "sign-up" ? "signup" : "login"; const dest = `${PLATFORM_URL}${AUTH_BASE}/${path}?return_to=${encodeURIComponent(returnTo)}`;