harden(app): migrate authToken to flutter_secure_storage
Merged
UN
2mo ago+234+234+012345678901234567890123456789-5-5-0123456789
What changed and why
Auth tokens were stored in plaintext SharedPreferences. This moves authToken into flutter_secure_storage (iOS/macOS Keychain, Android EncryptedSharedPreferences) with a one-time startup migration so existing logged-in sessions are not logged out. flutter_secure_storage was not previously used in the app; this adds the dependency rather than duplicating an existing token path.
Migration path and assumptions
- Startup:
SharedPreferencesUtil.init()(already called frommain.dart) runsmigrateAuthTokenFromPrefs()once, then loads the token into an in-memory cache so existing sync getters/setters keep working. - One-time: Prefs flag
authTokenSecureMigratedmakes migration idempotent. After success, any leftover prefsauthTokenis scrubbed. - Conflict rule: If secure storage already has a token, the prefs copy is discarded (never overwrites secure with stale prefs).
- Failure: If secure write fails, the prefs copy and migration flag are left alone so the next launch retries — users stay logged in.
- Scope: Only
authTokenmoves.tokenExpirationTimeand other identity fields (uid, email, names) stay in SharedPreferences (non-secret / display cache). - Clearing:
authToken = '',clearUserDisplayCache(), andclear()all clear the in-memory cache and delete the secure entry. - Tests: Under
FLUTTER_TESTwithout an injected store, an in-memory fallback is used so hermetic tests do not need the plugin channel. Migration tests inject a mockedFlutterSecureStorage.
Product invariants affected
none
How it was verified
flutter test test/unit/auth_token_secure_storage_migration_test.dart test/unit/auth_service_token_result_test.dart test/unit/clear_deleted_account_session_test.dart— all passedflutter analyze lib/backend/preferences.dart test/unit/auth_token_secure_storage_migration_test.dart— no issuesapp/scripts/analyze_ratchet.sh— passed- Bounded pre-push gate passed; full Flutter suite deferred to CI
Could not exercise a real device login → kill → relaunch path on this Linux cloud VM (no iOS/Android runtime here).
Tests
- New:
app/test/unit/auth_token_secure_storage_migration_test.dart— migrates legacy prefs token once; does not overwrite existing secure token; setter/clear round-trip; flutter_test fallback path - Existing auth/clear-session tests still pass with the new storage seam
Failure class (fixes)
Failure-Class: none

