From 4bfd0201254eaacb89732b23daba245c1c6ce281 Mon Sep 17 00:00:00 2001 From: Richard R Date: Fri, 12 Jun 2026 08:30:23 -0600 Subject: [PATCH] fix(auth): prevent unwanted anonymous session after logout by tracking session state Track previous session existence to avoid minting a new anonymous user when a session ends and the user is redirected to the sign-in page. This prevents clobbering account-scoped preferences by ensuring bootstrapping does not occur during the logout redirect flow. --- src/components/auth/AuthLoader.tsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/components/auth/AuthLoader.tsx b/src/components/auth/AuthLoader.tsx index 910e6d3..257bfb8 100644 --- a/src/components/auth/AuthLoader.tsx +++ b/src/components/auth/AuthLoader.tsx @@ -102,6 +102,7 @@ export function AuthLoader({ children }: { children: ReactNode }) { const [retryNonce, setRetryNonce] = useState(0); const attemptedForNullSessionRef = useRef(false); const clearingDisallowedAnonymousRef = useRef(false); + const hadSessionRef = useRef(false); const isAuthPage = pathname === '/signin' || pathname === '/signup'; // If the auth base URL changes, re-run the bootstrap logic. @@ -116,6 +117,7 @@ export function AuthLoader({ children }: { children: ReactNode }) { if (isPending) return; if (session) { + hadSessionRef.current = true; if (!allowAnonymousAuthSessions && session.user.isAnonymous) { if (clearingDisallowedAnonymousRef.current) return; clearingDisallowedAnonymousRef.current = true; @@ -154,11 +156,27 @@ export function AuthLoader({ children }: { children: ReactNode }) { // preferences such as the changelog "last seen version" and re-showing the // changelog on every fresh login. if (isAuthPage) { + hadSessionRef.current = false; setIsAutoLoggingIn(false); setBootstrapError(null); return; } + // A session just ended in this tab (sign-out or expiry) and we're still + // on an app page while the redirect to /signin is in flight. The session + // hook delivers `null` before `router.push('/signin')` finishes its + // server roundtrip, so `isAuthPage` is still false here — bootstrapping + // now would mint a replacement anonymous user that onLinkAccount links + // into the next login, clobbering account-scoped preferences. Redirect + // instead of bootstrapping; the ref resets once an auth page mounts. + if (hadSessionRef.current) { + setIsAutoLoggingIn(false); + setBootstrapError(null); + setIsRedirecting(true); + router.replace('/signin'); + return; + } + // Avoid double-calling anonymous sign-in (e.g. React strict mode). if (attemptedForNullSessionRef.current) return; attemptedForNullSessionRef.current = true;