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.

Diagram showing the relationships among the Security and LocalAuthentication frameworks, and the Secure Enclave, to securely store keychain items.

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 / APIAuth Prompt in Simulator
Use LAContext.evaluatePolicy(_:localizedReason:)Yes
Read a protected keychain item with kSecUseAuthenticationContextNo

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.

Did you find this article valuable?

Support Marco Eidinger by becoming a sponsor. Any amount is appreciated!