feat: implement cross-tab logout synchronization using storage event broadcasting
This commit is contained in:
@@ -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(() => {
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user