Definition
Before calling APIs that require login, confirm “has session resolution finished?” rather than assuming “not logged in right now.”
Auth resolution is the state where the app has restored a session from cookies/tokens or confirmed “no session.” Before that, user may briefly be null. Gating controls fetch on/off via React Query’s enabled. A typical expression is enabled: authResolved && isAuthenticated.
Why It Matters
Session restoration is async. If you hit protected resources during the loading window because you only see !user, you get 401 Unauthorized, and a global handler may send users to /login, breaking public home and SEO pages. Test MSW (mock network) may not return 401 or may hide timing, so the bug only reproduces in real browsers (no-cookie context).
How It Works
- The auth layer exposes
status: 'loading' | 'authenticated' | 'anonymous'(orresolved: boolean). - Protected queries:
enabled: status === 'authenticated'(orresolved && !!user). - Public/anonymous pages: set protected queries
enabled: false; use mock or static data only. - Do not define
isAnonymousas!useralone — true during loading causes wrong anonymous UI and wrong fetches. - Apply global 401→login redirect only on protected routes, or exempt public paths.
Practical Application
- Public landing/home: meta, JSON-LD, FAQ from server/static; turn off workspace API.
- Header/tab clicks: show login dialog for anonymous users instead of navigating.
- E2E: do not conclude “anonymous OK” from MSW alone; verify network 401 in cookie-isolated real browser.
- Loading UI: spinner/skeleton when
resolved === false; lock panel only after anonymous is confirmed.
Trade-offs
| Choice | Upside | Cost |
|---|---|---|
| Strict gate | Stable public pages | Data gap before resolution (skeleton needed) |
Fetch on !user only | Simple implementation | 401 and redirect during loading window |
| Global 401→login | Simple security UX | Conflicts with SEO and anonymous preview |
When Not to Use
- Adding excessive auth gates on pages that only use public APIs, causing unnecessary delay.
- Duplicating client-side blocking when server components already resolved session, hiding the real cause (document the boundary).
Common Mistakes
isAnonymous = !user→ treated as anonymous during loading.- E2E green, login bounce only in production.
- 401 handler sends all fetch failures to
/login— including public 404/network errors.
Related Concepts
- race-safe-async-ui-requests — Cancel requests and apply only the latest response
- structured-data-visible-content-parity — Content rules when public home is open