critical priority low complexity infrastructure pending infrastructure specialist Tier 1

Acceptance Criteria

NSFaceIDUsageDescription key is present in ios/Runner/Info.plist with a Norwegian user-facing string explaining why Face ID is needed (e.g., 'Vi bruker Face ID for å logge deg inn raskt og sikkert.')
NSFaceIDUsageDescription value is also provided in English as a fallback (or separate Localizable.strings entry exists for 'en')
Keychain Sharing entitlement is present in ios/Runner/Runner.entitlements (or created if not existing)
flutter build ios --simulator completes without code signing errors or missing entitlement warnings related to Keychain
App launches on iOS simulator without crashing on startup
Running flutter analyze after the changes shows no new warnings
The Info.plist change is committed and the diff shows only the NSFaceIDUsageDescription addition — no other unintended keys modified

Technical Requirements

frameworks
local_auth (iOS platform integration)
flutter_secure_storage (Keychain dependency)
Xcode project configuration (Runner.xcodeproj)
apis
iOS LocalAuthentication framework (LAContext) — platform-level
iOS Keychain Services — platform-level
performance requirements
iOS build time must not increase by more than 10 seconds due to these configuration changes
security requirements
NSFaceIDUsageDescription must be honest and specific — App Store review rejects vague strings like 'for authentication'
Keychain entitlements must use the app's actual bundle identifier group — do not use a wildcard
Do not add NSCameraUsageDescription or other unrelated permissions in the same change

Execution Context

Execution Tier
Tier 1

Tier 1 - 540 tasks

Can start after Tier 0 completes

Implementation Notes

Edit ios/Runner/Info.plist directly in a text editor or via Xcode — avoid using Xcode's Info.plist GUI editor as it can reorder keys and create noisy diffs. Add the NSFaceIDUsageDescription key as a string entry: 'NSFaceIDUsageDescriptionVi bruker Face ID for å logge deg inn raskt og sikkert.'. For Keychain entitlements, open ios/Runner/Runner.entitlements (create it if absent) and add the keychain-access-groups array with the app's bundle ID prefix. If the project already uses flutter_secure_storage, Keychain entitlements are likely already configured — verify before adding to avoid duplication.

Note: Touch ID does not require a usage description key on iOS — only Face ID does. Do not confuse the two. The simulator supports Face ID simulation via Hardware → Face ID menu in the iOS Simulator app. TestFlight distribution (used for user testing) requires a real device provisioning profile with biometric entitlements — flag this for the build/release engineer.

Testing Requirements

After making the Info.plist and entitlements changes, run flutter build ios --simulator and confirm the build succeeds with exit code 0. Launch the built app on an iOS 16+ simulator and verify it reaches the home or login screen without crash. Manually trigger a local_auth canCheckBiometrics call (via a temporary debug button or existing auth flow) on the simulator and confirm it returns a value without throwing MissingPluginException or entitlement errors. Review the Xcode build log for any code signing or entitlement warnings.

No automated test files are required for this infrastructure task.

Component
Local Auth Integration
infrastructure low
Epic Risks (3)
high impact medium prob technical

iOS Keychain access requires correct entitlement configuration and provisioning profile setup. Misconfigured entitlements cause silent failures in CI/CD and on physical devices, where the plugin appears to work in the simulator but fails at runtime. This can delay foundation delivery and block all downstream epics.

Mitigation & Contingency

Mitigation: Add a dedicated integration test running on a physical iOS device early in the epic. Document required entitlements and provisioning steps in a developer runbook. Validate Keychain access in the CI pipeline using an iOS simulator with correct entitlements enabled.

Contingency: If Keychain entitlements cannot be resolved quickly, temporarily use in-memory storage behind the SecureSessionStorage interface to unblock downstream epics, then resolve the Keychain issue in a hotfix before release.

medium impact medium prob dependency

The Flutter local_auth plugin has a history of breaking API changes between major versions, and its Android implementation depends on BiometricPrompt which behaves differently across Android API levels (23-34). An incompatible plugin version or unexpected Android API behaviour can cause authentication failures on a significant portion of the target device fleet.

Mitigation & Contingency

Mitigation: Pin local_auth to a specific stable version in pubspec.yaml. Test against Android API levels 23, 28, and 33 in the CI matrix. Review the plugin changelog and migration guide before adopting any version bump.

Contingency: If the pinned version proves incompatible with target devices, evaluate flutter_local_auth_android as a replacement or fork the plugin adapter to isolate the breaking surface.

high impact low prob security

If users upgrade from a version of the app that stored session data in non-encrypted storage (SharedPreferences), a migration path is required. Failing to migrate silently leaves old tokens in plain storage, creating a security gap and potentially causing confusing authentication state on first launch of the new version.

Mitigation & Contingency

Mitigation: Audit existing storage usage across the codebase before writing SecureSessionStorage. If legacy plain storage keys exist, implement a one-time migration routine that reads from SharedPreferences, writes to Keychain/Keystore, and deletes the plain-text entry.

Contingency: If migration is discovered late, ship the migration as a mandatory patch release before the biometric feature is enabled for users, and add a startup check that blocks biometric opt-in until migration is confirmed complete.