harden(app): migrate authToken to flutter_secure_storage

Merged
UN
2mo ago
+234-5

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

  1. Startup: SharedPreferencesUtil.init() (already called from main.dart) runs migrateAuthTokenFromPrefs() once, then loads the token into an in-memory cache so existing sync getters/setters keep working.
  2. One-time: Prefs flag authTokenSecureMigrated makes migration idempotent. After success, any leftover prefs authToken is scrubbed.
  3. Conflict rule: If secure storage already has a token, the prefs copy is discarded (never overwrites secure with stale prefs).
  4. Failure: If secure write fails, the prefs copy and migration flag are left alone so the next launch retries — users stay logged in.
  5. Scope: Only authToken moves. tokenExpirationTime and other identity fields (uid, email, names) stay in SharedPreferences (non-secret / display cache).
  6. Clearing: authToken = '', clearUserDisplayCache(), and clear() all clear the in-memory cache and delete the secure entry.
  7. Tests: Under FLUTTER_TEST without an injected store, an in-memory fallback is used so hermetic tests do not need the plugin channel. Migration tests inject a mocked FlutterSecureStorage.

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 passed
  • flutter analyze lib/backend/preferences.dart test/unit/auth_token_secure_storage_migration_test.dart — no issues
  • app/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

Open in Web Open in Cursor