diff --git a/src/app/logout/page.tsx b/src/app/logout/page.tsx index f4dcc13..c8fa7e9 100644 --- a/src/app/logout/page.tsx +++ b/src/app/logout/page.tsx @@ -13,6 +13,9 @@ export default function LogoutPage() { localStorage.setItem('isLoggingOut', 'true'); localStorage.removeItem('accessToken'); localStorage.removeItem('refreshToken'); + // Broadcast to other open tabs so they also log out. + // 'storage' events only fire in OTHER tabs, not the one that wrote the value. + localStorage.setItem('re-quest-logout-broadcast', String(Date.now())); } useEffect(() => { diff --git a/src/components/providers/session-provider.tsx b/src/components/providers/session-provider.tsx index 75ca7ed..bc0bcb1 100644 --- a/src/components/providers/session-provider.tsx +++ b/src/components/providers/session-provider.tsx @@ -4,6 +4,37 @@ import { SessionProvider as NextAuthSessionProvider, useSession } from "next-aut import { useEffect, useRef } from "react"; import { HeaderProvider } from "./header-provider"; +const LOGOUT_BROADCAST_KEY = "re-quest-logout-broadcast"; + +// Listens for logout broadcasts from OTHER tabs and forces this tab to reload. +// When the logout page clears auth, it writes a timestamp to LOGOUT_BROADCAST_KEY; +// every other open tab receives a `storage` event and reloads into an unauthed state. +function CrossTabLogoutListener() { + useEffect(() => { + const onStorage = (e: StorageEvent) => { + if (e.key !== LOGOUT_BROADCAST_KEY || !e.newValue) return; + // Skip auth pages — they're already unauthed. + const path = window.location.pathname; + const onAuthPage = + path === "/login" || + path === "/signup" || + path === "/logout" || + path === "/" || + path.startsWith("/forgot-password") || + path.startsWith("/reset-password"); + if (onAuthPage) return; + // Clear local auth and hard-redirect to /logout so this tab runs the full cleanup too. + localStorage.removeItem("accessToken"); + localStorage.removeItem("refreshToken"); + localStorage.removeItem("user"); + window.location.replace("/logout"); + }; + window.addEventListener("storage", onStorage); + return () => window.removeEventListener("storage", onStorage); + }, []); + return null; +} + // Component that syncs tokens from NextAuth session to localStorage function TokenSync() { const { data: session, status } = useSession(); @@ -63,6 +94,7 @@ export function SessionProvider({ children }: { children: React.ReactNode }) { return ( + {children}