sojorn/sojorn_docs/troubleshooting/READ_FIRST.md

2.6 KiB

ARCHITECTURAL CONSTRAINT: SUPABASE AUTHENTICATION & TOKEN MANAGEMENT

CRITICAL RULE: You are STRICTLY FORBIDDEN from implementing manual JWT refresh logic, manual token expiration checks, or custom 401 retry loops in ApiService or any other service.

Context: The Supabase Flutter SDK (supabase_flutter) manages the session lifecycle, token refreshing, and persistence automatically. Previous attempts to manually refresh sessions created a race condition with the SDK, triggering Supabase's "Token Reuse Detection," which invalidates the user's entire session family and logs them out.

Enforcement Guidelines:

  1. NO Manual Refreshes:

    • Never call supabase.auth.refreshSession() manually inside API interceptors or service methods.
    • Never strictly check session.expiresAt before making a call. Trust the SDK to handle the header.
    • Forbidden Pattern: if (tokenExpired) await refreshSession();
  2. NO Custom 401 Handling:

    • Do not wrap API calls in try/catch blocks that specifically catch 401 Unauthorized to attempt a re-login or refresh.
    • If a 401 occurs, allow the error to bubble up. The app's AuthGate (listening to the onAuthStateChange stream) will handle the logout naturally.
  3. Required Initialization Pattern (main.dart):

    • Always initialize Supabase with the PKCE flow to ensure stability on mobile.
    • Code Standard:
      await Supabase.initialize(
        url: ...,
        anonKey: ...,
        authOptions: const FlutterAuthClientOptions(
          authFlowType: AuthFlowType.pkce, // MANDATORY
          autoRefreshToken: true,
        ),
      );
      
  4. Required Edge Function Call Pattern (api_service.dart):

    • Use the SDK's functions.invoke method. It automatically injects the correct, fresh Bearer token.
    • Code Standard:
      // DO THIS:
      final response = await _supabase.functions.invoke('function-name', ...);
      
      // DO NOT DO THIS:
      // final token = _supabase.auth.currentSession.accessToken;
      // final response = http.post(..., headers: {'Authorization': 'Bearer $token'});
      
  5. State Management (auth_provider.dart):

    • User state must always be derived reactively from supabase.auth.authStateChanges. Never rely on a static User? variable that might become stale.

Correction Protocol: If you encounter code that violates these rules (e.g., variables like _refreshCooldown or _refreshInFlight), DELETE IT IMMEDIATELY and refactor to use the standard SDK methods.