feat: implement cross-tab logout synchronization using storage event broadcasting

This commit is contained in:
pradeepkumar
2026-04-15 23:52:05 +05:30
parent c60978aea1
commit 5cac15d742
2 changed files with 35 additions and 0 deletions

View File

@@ -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(() => {

View File

@@ -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 (
<NextAuthSessionProvider>
<TokenSync />
<CrossTabLogoutListener />
<HeaderProvider>
{children}
</HeaderProvider>