Authentication & Session Management: Best Practices and Troubleshooting
This guide covers:
- How token expiry and refresh works (with Supabase as an example)
- Common causes of refresh token errors
- Industry standards for handling authentication in modern web/mobile apps
- Practical recommendations for React/React Native
- A reusable checklist for robust auth integration
1. Token Expiry: How Fast and Why?
- Access Token (JWT): Usually expires in 1 hour (Supabase default).
- Refresh Token: Valid for weeks/months, but can be invalidated on logout, password change, or security events.
- If tokens seem to expire too fast:
- The refresh token may not be persisted or is lost (e.g., storage/cookie issues).
- The user logs out elsewhere, or Supabase invalidates all tokens for security.
- The app is running in incognito/private mode or with strict browser settings.
2. Common Causes of refresh_token_not_found
- User logs out in another tab/device (global logout).
- Refresh token is not stored or is cleared (storage/cookie issues).
- Refresh token is corrupted or not sent with the request.
- Supabase project/client misconfiguration (wrong domain, cookie settings, etc.).
- Running in an environment with no persistent storage.
3. Industry Standard: How to Handle Auth
a. Service Pattern (Recommended)
- Use a dedicated service (e.g.,
authService) for all auth logic: sign in, sign out, refresh, get user, etc. - The service manages token storage, refresh, and error handling.
b. State Management
- Use React Query, Zustand, Redux, or similar for global auth state (session, user, loading, error).
- React Query is ideal for session/user queries and cache invalidation.
c. Context
- Use React Context to provide auth state/actions to the component tree.
- Avoid putting all logic in context—prefer service + state.
d. Error Handling
- Globally catch auth errors (especially refresh token errors).
- On
refresh_token_not_found, force logout, clear all state, redirect to login, and show a user-friendly message.
e. Session Persistence
- Store tokens securely (AsyncStorage for RN, httpOnly cookies or localStorage for web).
- Restore session on app start (hydrate from storage).
- Listen for auth state changes (e.g., Supabase’s
onAuthStateChange).
f. UX
- Never block the UI for token refresh.
- Show a friendly message and redirect to login if session expires.
- Optionally, allow “remember me” for longer refresh token life.
4. Best Practice Flow
- User logs in: Store access and refresh tokens securely.
- User navigates app: Use access token for API calls.
- Access token expires: Use refresh token to get a new access token (handled by Supabase client).
- Refresh token fails:
- Detect error (
refresh_token_not_found). - Force logout, clear all state, redirect to login, and show a message.
- Detect error (
- User logs out: Invalidate tokens and clear all state/storage.
5. Troubleshooting Checklist (Reusable)
- Are you using the latest Supabase (or auth provider) client?
- Are tokens (access/refresh) stored securely and persistently?
- Is session restored on app start (hydration)?
- Are you handling logout and session expiration globally?
- Do you catch and handle
refresh_token_not_founderrors everywhere (service, queries, global error boundary)? - Do you clear all state and storage on logout or session expiration?
- Do you show a user-friendly message and redirect to login on session expiration?
- Are you listening for auth state changes (e.g.,
onAuthStateChange)? - Are you testing in both normal and incognito/private modes?
- Are your Supabase project and client configs correct (domain, cookies, etc.)?
For more details, see your authService.ts, useAuthQuery.ts, and global error handling logic.