Skip to main content

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

  • 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

  1. User logs in: Store access and refresh tokens securely.
  2. User navigates app: Use access token for API calls.
  3. Access token expires: Use refresh token to get a new access token (handled by Supabase client).
  4. Refresh token fails:
    • Detect error (refresh_token_not_found).
    • Force logout, clear all state, redirect to login, and show a message.
  5. 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_found errors 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.