Elysia's set.redirect returns 200 OK instead of 302 redirect on the
current version. Use set.status = 302 + set.headers['Location'] instead
for both /auth/google (Google OAuth redirect) and /auth/google/callback
(all redirect paths: errors, success token delivery).
Co-Authored-By: Claude <noreply@anthropic.com>
API (apps/api/src/routes/auth.ts):
- Exchange authorization code for tokens via Google's token endpoint
- Decode id_token payload (JWT) to extract sub, email, name
- Find user by googleId → fall back to email match (link accounts)
- Auto-create user if neither found (role: 'user', no password)
- Create session + set cookie, redirect to /login?token=<token>
Web (apps/web/src/pages/login-page.tsx):
- Consume ?token= query param from OAuth redirect
- Store token in localStorage for future API calls
- Fetch /auth/me to hydrate Zustand store, then navigate to dashboard
- Show OAuth errors from ?error= query param
Co-Authored-By: Claude <noreply@anthropic.com>
Android WebView blocks third-party cookies by default. This patch:
- Returns session token in login/register response body
- Stores token in localStorage, sends via Authorization: Bearer header
- Backend getCurrentUser supports Authorization header fallback
Co-Authored-By: Claude <noreply@anthropic.com>
- Cookie SameSite now dynamic: None;Secure when behind HTTPS proxy, Lax otherwise
- AuthGuard useEffect no longer overwrites Zustand store with null from background refetch
- AuthInitializer: add staleTime 30s
Co-Authored-By: Claude <noreply@anthropic.com>