fix(auth): sync logout across browser tabs

Listen for localStorage token changes so other open pages clear session state when one tab signs out.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
hansjone 2026-07-30 02:34:25 +00:00
parent b540ea21c1
commit a3bdad5be1
2 changed files with 26 additions and 2 deletions

View file

@ -7,7 +7,14 @@ import {
useState,
type ReactNode,
} from "react";
import { apiGet, apiPost, clearAuthToken, getAuthToken, setAuthToken } from "../services/api";
import {
AUTH_TOKEN_KEY,
apiGet,
apiPost,
clearAuthToken,
getAuthToken,
setAuthToken,
} from "../services/api";
export type AuthUser = {
id: string;
@ -62,6 +69,23 @@ export function AuthProvider({ children }: { children: ReactNode }) {
})();
}, [refreshMe]);
// Other tabs keep React auth state until they hear localStorage change.
// `storage` fires only in *other* documents — used to sync logout/login.
useEffect(() => {
const onStorage = (ev: StorageEvent) => {
if (ev.storageArea && ev.storageArea !== localStorage) return;
if (ev.key !== null && ev.key !== AUTH_TOKEN_KEY) return;
if (ev.key === null || ev.newValue == null || ev.newValue === "") {
setToken(null);
setUser(null);
return;
}
void refreshMe();
};
window.addEventListener("storage", onStorage);
return () => window.removeEventListener("storage", onStorage);
}, [refreshMe]);
const login = useCallback(async (username: string, password: string) => {
const data = await apiPost<{ access_token: string; user: AuthUser }>("/v1/auth/login", {
username,

View file

@ -25,7 +25,7 @@ import type {
TopologyMapItem,
} from "../types";
const AUTH_TOKEN_KEY = "netx_access_token";
export const AUTH_TOKEN_KEY = "netx_access_token";
export const getAuthToken = (): string | null => {
try {