Summary
Currently, auth tokens are stored in localStorage, which means the server cannot access them during SSR. This causes the auth UI (login button vs user menu) to "pop in" after hydration.
Current Behavior
- Server renders page with no auth state (can't access localStorage)
- Browser hydrates with loading state
- useEffect reads localStorage, finds tokens
- UI re-renders with authenticated state
- User sees profile button "pop in"
Desired Behavior
Server should know auth state during SSR and render the correct UI immediately, with no pop-in.
Solution
Store auth tokens in HTTP-only cookies instead of localStorage:
Backend changes:
- Set
access_token and refresh_token as HTTP-only, Secure, SameSite cookies on login/callback
- Read tokens from cookies in auth middleware
- Clear cookies on logout
Frontend changes:
- Remove localStorage token storage
- Credentials included automatically via
credentials: 'include'
- Server components can check auth via cookies
Benefits:
- No hydration mismatch for auth UI
- More secure (HTTP-only cookies not accessible to XSS)
- Simpler frontend code (no manual token management)
Trade-offs:
- CSRF protection needed (but we already have signed state tokens)
- Cookies sent on every request (minor overhead)
Related
Summary
Currently, auth tokens are stored in localStorage, which means the server cannot access them during SSR. This causes the auth UI (login button vs user menu) to "pop in" after hydration.
Current Behavior
Desired Behavior
Server should know auth state during SSR and render the correct UI immediately, with no pop-in.
Solution
Store auth tokens in HTTP-only cookies instead of localStorage:
Backend changes:
access_tokenandrefresh_tokenas HTTP-only, Secure, SameSite cookies on login/callbackFrontend changes:
credentials: 'include'Benefits:
Trade-offs:
Related