Summary
The OAuth callback returns the master JWT in a URL query parameter, and the frontend stores the token in localStorage plus a JavaScript-written cookie. This increases token exposure through browser history, logs, referrers/telemetry, and XSS.
Evidence
- OAuth login redirects to
/oauth/success?token=...: internal/master/api/oauth/callback.go:147.
- The success page reads the token from the URL and stores it in
localStorage: web/src/app/(auth)/oauth/success/page.tsx:13 and web/src/app/(auth)/oauth/success/page.tsx:21.
- The same page writes a JS-readable cookie without
HttpOnly or Secure: web/src/app/(auth)/oauth/success/page.tsx:22.
- Password login uses the same
localStorage plus JS-readable cookie pattern: web/src/lib/auth.ts:33.
- API requests read the bearer token from
localStorage: web/src/lib/api/client.ts:21.
Risk
Bearer tokens are easier to exfiltrate or accidentally log. Cleaning the URL after the page loads helps, but it does not prevent exposure in the redirect itself or before the client script runs.
Proposed fix
- Replace query-token delivery with a server-side session exchange, short-lived one-time code, or
HttpOnly; Secure; SameSite cookie set by the server.
- Avoid storing bearer tokens in
localStorage.
- If browser-side bearer tokens remain necessary, document the tradeoff and add strict CSP/XSS hardening.
Acceptance criteria
- OAuth success redirects no longer include a JWT or long-lived bearer token in the URL.
- Authentication works without reading the JWT from
localStorage.
- Cookies used for authentication are server-set with
HttpOnly, Secure, and an explicit SameSite policy.
Summary
The OAuth callback returns the master JWT in a URL query parameter, and the frontend stores the token in
localStorageplus a JavaScript-written cookie. This increases token exposure through browser history, logs, referrers/telemetry, and XSS.Evidence
/oauth/success?token=...:internal/master/api/oauth/callback.go:147.localStorage:web/src/app/(auth)/oauth/success/page.tsx:13andweb/src/app/(auth)/oauth/success/page.tsx:21.HttpOnlyorSecure:web/src/app/(auth)/oauth/success/page.tsx:22.localStorageplus JS-readable cookie pattern:web/src/lib/auth.ts:33.localStorage:web/src/lib/api/client.ts:21.Risk
Bearer tokens are easier to exfiltrate or accidentally log. Cleaning the URL after the page loads helps, but it does not prevent exposure in the redirect itself or before the client script runs.
Proposed fix
HttpOnly; Secure; SameSitecookie set by the server.localStorage.Acceptance criteria
localStorage.HttpOnly,Secure, and an explicitSameSitepolicy.