Get the biometric authentication prompt for protected keychain items in the iOS simulator
In this blog post, I'll recap how to protect a keychain item with biometric authentication. Then, I'll show how you can ensure you get a prompt for biometric authentication in the iOS simulator.
In a previous blog post, I explained that Apple's LocalAuthentication
framework provides a universal API independent of which biometric authentication type is used.
By using its LAContext.evaluatePolicy(_:localizedReason:)
you can ensure that the user gets prompted for biometric authentication while the app runs on a device OR in the simulator.
You can protect a keychain item with biometric authentication by instructing keychain services to seek the user’s permission by authenticating the user biometrically with Face ID, Touch ID, or Optic ID.
You interact with the keychain through Apple's Security
framework, which delegates the task of presenting the appropriate authentication user interface to the LocalAuthentication
framework.
However, an important part here is missing on a simulator: the Secure Enclave.
The Secure Enclave is only present on physical devices and carries out the authentication by, for example, testing the user’s finger against the stored fingerprints. The Secure Enclave would then return a pass/fail result that gates keychain item access.
Several developers complained that setting up protection with kSecAttrAccessControl will not show a biometric prompt in a simulator when reading that item. The keychain item's value will always be returned in the simulator.
No wonder developers and testers can get confused because Apple's APIs behave differently:
Use Case / API | Auth Prompt in Simulator |
Use LAContext.evaluatePolicy(_:localizedReason:) | Yes |
Read a protected keychain item with kSecUseAuthenticationContext | No |
To make the experience in the simulator comparable, you can write a decorator that ensures a biometric prompt in the simulator by explicitly calling LAContext.evaluatePolicy(_:localizedReason:)
before invoking your function to read the keychain item.
Here is the respective GitHub gist.
The user will be prompted for biometric authentication and can then choose if the biometric authentication was successful or not.
The whole project to demonstrate these two behaviors is open-sourced and available on GitHub.