Implement Encrypted Local Session Cache
epic-email-password-login-foundation-task-006 — Set up flutter_secure_storage as the encrypted device storage backend in AuthRepository for caching the Supabase session token and refresh token. Implement read, write, and delete operations with proper error handling for storage permission failures. Ensure the cached session survives app restarts and is cleared on explicit sign-out.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 1 - 540 tasks
Can start after Tier 0 completes
Implementation Notes
supabase_flutter 2.x already integrates with flutter_secure_storage for session persistence via the authFlowType and localStorage parameters in Supabase.initialize(). Before implementing a custom cache, verify whether Supabase.initialize(localStorage: SecureStorageLocalStorage()) already covers the persistence requirement — if so, AuthRepository only needs to call signOut() to clear. If custom control is needed (e.g., multi-org session management required by NHF's up-to-5-locallag membership), wrap the Supabase session localStorage with a prefixed key scheme per org. Key naming convention: 'auth.{orgId}.access_token'.
For the MVP (single org context), plain keys suffice. The iOS KeychainAccessibility setting is critical: first_unlock_this_device allows the app to read tokens after a restart without requiring the user to unlock the phone first — important for background refresh.
Testing Requirements
Unit tests with flutter_test using a MockFlutterSecureStorage (implement the FlutterSecureStorage interface): (1) cacheSession() calls write() for both token keys; (2) loadCachedSession() returns null when storage is empty; (3) loadCachedSession() returns reconstructed Session when both keys present; (4) clearSession() calls delete() for both keys; (5) PlatformException from write() is caught and rethrown as StorageException. Integration test on a real device (iOS via TestFlight, Android via direct install): write session, kill app, relaunch, assert tokens readable. Do not use emulators for keychain/keystore tests — they behave differently from physical devices.
Supabase client initialization may fail silently in certain Flutter environments if environment variables are missing or the anon key is rotated, leading to runtime null-pointer errors throughout the auth layer.
Mitigation & Contingency
Mitigation: Add explicit assertion checks during app startup that verify the Supabase client is initialized before the router resolves. Document required --dart-define keys in the project README and add a CI step that validates their presence.
Contingency: Implement a fallback initialization error screen with a clear message and a retry button. Log initialization failures to crash reporting immediately.
The flutter_secure_storage package behaviour differs between iOS Keychain and Android Keystore implementations. On Android, biometric-enrolled devices may require additional authentication to read stored tokens, causing unexpected session read failures.
Mitigation & Contingency
Mitigation: Test the repository on Android devices with and without biometric enrollment early in development. Use accessibility options in flutter_secure_storage to configure whether biometric authentication is required for storage access.
Contingency: If biometric-gated storage causes regressions, fall back to a non-biometric storage option for session tokens (reserving biometric-gated storage for higher-sensitivity credentials only).