feat(auth): add server-backed demo sessions
The browser treated sessionStorage as the source of truth for the logged-in user and never verified or invalidated the server-side session cookie: no GET /api/v1/demo/session or POST /api/v1/demo/logout endpoint existed, and a central 401 handler was defined but never wired up. Add both endpoints; the session-check response is marked Cache-Control: no-store to avoid the browser serving a stale "authenticated" response right after logout. AuthProvider now verifies against the server on every mount (sessionStorage only caches presentation state to avoid a login-screen flash), subscribes to a central 401 listener on the API client, and RequireAuth shows a loading state during verification instead of flashing protected content or the wrong role.
This commit is contained in:
@@ -1,5 +1,13 @@
|
||||
const API_BASE = import.meta.env.VITE_API_BASE_URL ?? "";
|
||||
|
||||
type UnauthorizedListener = () => void;
|
||||
const unauthorizedListeners = new Set<UnauthorizedListener>();
|
||||
|
||||
export function onUnauthorized(listener: UnauthorizedListener): () => void {
|
||||
unauthorizedListeners.add(listener);
|
||||
return () => unauthorizedListeners.delete(listener);
|
||||
}
|
||||
|
||||
export class ApiError extends Error {
|
||||
status: number;
|
||||
code: string;
|
||||
@@ -31,6 +39,9 @@ async function request<T>(path: string, init?: RequestInit): Promise<T> {
|
||||
body = undefined;
|
||||
}
|
||||
const error = body?.error;
|
||||
if (response.status === 401) {
|
||||
unauthorizedListeners.forEach((listener) => listener());
|
||||
}
|
||||
throw new ApiError(
|
||||
response.status,
|
||||
error?.code ?? String(response.status),
|
||||
|
||||
Reference in New Issue
Block a user