Purpose

How the SPA acquires and stores a JWT to call /api/* endpoints.

Pieces

  • frontend/kundkort/hooks/useAuth.ts — token state, login, logout
  • frontend/kundkort/components/LoginModal.tsx — email/password form
  • frontend/kundkort/app.tsx:98-100 — gates the app: !token renders <LoginModal>, otherwise renders <KundkortPage> or <SearchPage>

Token storage

sessionStorage key enrichnode_jwt (useAuth.ts:3). Token is read once on mount via useState initializer (useAuth.ts:17-28). Cleared on logout().

Login

POST /api/auth/login with { email, password }. On 401 the modal shows “Felaktigt e-post eller lösenord”; other errors fall through to “Inloggning misslyckades — försök igen” (useAuth.ts:39-44). Success reads data.token and stashes it.

DEV_MODE auto-login

Warning

useAuth.ts:6 has a hard-coded const DEV_MODE = true. When set, the hook synchronously stuffs 'dev-token' into sessionStorage on first mount and skips the login modal entirely (useAuth.ts:22-26). The login form is unreachable until this flag is flipped to false. Production deploys must set it to false.

The backend separately exposes dev_mode via GET /api/config for the footer DEVMODE badge — this comes from KEYCLOAK_DEV_MODE env var (src/api/index.ts:115-124), independent of the frontend flag.

Token usage

Every fetch call sends Authorization: Bearer ${token}. See Kundkort API Client for the full set of endpoints.

Logout flow

onLogout in app.tsx:47-50 calls useAuth.logout() then navigates back to the search view, also clearing ?org= from the URL.

See also

Kundkort API Client, Kundkort Page, Search Page, Frontend Overview.

See also