Auth Domain
This domain covers the public authentication pages under
frontend/src/pages/auth and how they integrate with
the global auth state and route guards.
1️⃣ Domain Purpose
The Auth domain provides a minimal, predictable entry/exit experience: - Start Google OAuth2 login (full-page redirect via backend). - Handle the OAuth callback and hydrate the SPA user session. - Support a client-only Demo Mode for read-only exploration. - Perform logout in a way that reliably invalidates the server session.
2️⃣ Scope & Boundaries
Included: - LoginPage.tsx (SSO entry + Demo Mode
entry) - AuthCallback.tsx (session verification via
/api/me) - LogoutPage.tsx (client
cleanup + backend logout via POST form) -
LogoutSuccess.tsx (confirmation screen)
Related (cross-cutting, but auth-owned behavior): -
AuthContext session hydration + demo persistence
(frontend/src/context/auth/AuthContext.ts) - Route
guarding (RequireAuth) and route placement in the
router - Proactive session checking
(useSessionTimeout) in the authenticated shell
Excluded: - Global route definitions and shell layout: see Routing and App Shell - HTTP client/auth redirect rules: see Data Access - Auth state API and constraints: see Auth Context
3️⃣ High-Level Diagram
4️⃣ Domain Notes (Implementation-facing)
- Auth is implemented as public pages plus
global state:
- Pages under
src/pages/auth/*are intentionally minimal and don’t own global routing. AuthContextis the single source of truth foruser,loading, andlogoutInProgress.
- Pages under
- Session hydration order (in
AuthContext):- Restore Demo user from
localStorage(keyssp.demo.session) if present. - Otherwise call
GET /api/meto hydrate a real user session.
- Restore Demo user from
- OAuth2 entry is a full-page redirect
(
window.location.assign):useAuth().login()builds a backend URL like${API_BASE}/oauth2/authorization/google?return=<origin>.- The SPA expects to land back on
/authafter backend auth completes.
- Logout is also a full navigation using a
top-level form POST:
- Avoids XHR/CORS and ensures server-side session invalidation.
- Cleanup responsibilities are centralized in
LogoutPage:- React Query cache cleared via
queryClient.clear(). - Client auth state cleared via
useAuth().logout().
- React Query cache cleared via
- Guard semantics (
RequireAuth):- While auth is bootstrapping (
loading=true) it renders a fallback instead of routing. logoutInProgressacts like a temporary “loading” state to prevent flashing/loginduring teardown.- Demo users are treated as authenticated, but routes can opt
out by omitting
allowDemo.
- While auth is bootstrapping (
5️⃣ Domain Map (Deep-dives)
Leaf docs for how Auth works:
Related ADRs
- ADR-0006: Global state with Context modules (Auth)
- ADR-0005: Application shell split (authenticated vs public)
- ADR-0002: API layer abstraction (httpClient 401 rules + /api/me)