iOS biometric authentication with Face ID and Touch ID

Mar 27, 2024#ios#security

Biometric authentication refers to the use of biological characteristics, such as fingerprints or facial features, to verify the identity of a user. iOS devices, such as iPhones and iPads, incorporate biometric authentication features primarily through Touch ID and Face ID.

  • Touch ID: This feature utilizes a fingerprint sensor embedded in the device’s home button (or power button in newer models) to scan and authenticate the user’s fingerprint.
  • Face ID: Introduced with the iPhone X and subsequent models, Face ID uses facial recognition technology to authenticate users. It relies on the TrueDepth camera system located at the top of the device’s screen, which projects infrared dots to create a depth map of the user’s face.

Both Touch ID and Face ID are designed to provide secure and convenient authentication methods for users, offering an alternative to traditional passcodes or passwords.

Users love biometric authentication because this mechanism let them access their devices securely, with minimal effort. When you adopt the LocalAuthentication framework, you streamline the user authentication experience in the typical case, while providing a fallback option for when biometrics aren’t available.

Set usage description

In any project that uses biometrics, include the NSFaceIDUsageDescription key in your app’s Info.plist file. Without this key, the system won’t allow your app to use Face ID.

The value for this key is a string that the system presents to the user the first time your app attempts to use Face ID. The string should clearly explain why your app needs access to this authentication mechanism.

The system doesn’t require a comparable usage description for Touch ID.

Create and configure a context

You perform biometric authentication in your app using an LAContext instance, which brokers interaction between your app and the Secure Enclave. Begin by creating a context:

var context = LAContext()

You can customize the messaging used by the context to guide the user through the flow. For example, you can set a custom message for the Cancel button that appears in various alert views:

context.localizedCancelTitle = "Enter Username/Password"

This helps the user understand that when they tap the button, they’ll be reverting to your normal authentication procedure.

Test policy availability

Before attempting to authenticate, test to make sure that you actually have the ability to do so by calling the canEvaluatePolicy(_:error:) method:

var error: NSError?
guard context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) else {
    print(error?.localizedDescription ?? "Can't evaluate policy")

    // Fall back to a asking for username and password.
    // ...
    return
}

Choose a value from the LAPolicy enumeration for which to test. The policy controls how the authentication behaves. For example, the deviceOwnerAuthentication policy used in this sample indicates that reverting to a passcode is allowed when biometrics fails or is unavailable.

Alternatively, you can indicate the deviceOwnerAuthenticationWithBiometrics policy, which doesn’t allow reverting to the device passcode.

Evaluate a policy

When you’re ready to authenticate, call the evaluatePolicy(_:localizedReason:reply:) method, using the same policy you already tested:

Task {
    do {
        try await context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: "Log in to your account")
        state = .loggedin
    } catch let error {
        print(error.localizedDescription)

        // Fall back to a asking for username and password.
        // ...
    }
}

For Touch ID, or when the user enters a passcode, the system displays the reason for authenticating that you provided in the method call. It’s important to provide a clear explanation, localized for any regions in which you operate, of why your app is asking the user to authenticate. The name of your app already appears before the reason you give, so you don’t need to include that in your message.

Adjust your user interface to accommodate Face ID

Aside from the biometric scanning operation itself, Face ID exhibits an important difference from Touch ID. When your app tries to use Touch ID, a system message asks the user to present a finger to scan. The user has time to think about and possibly abort the operation by canceling the prompt.

When your app invokes Face ID, the device begins scanning the user’s face right away. Users don’t get a final opportunity to cancel. To accommodate this behavioral difference, you might want to provide a different UI, depending on the kind of biometrics available on the device.

Provide a fallback alternative to biometrics

For various reasons, authentication sometimes fails or is unavailable:

  • The user’s device doesn’t have Touch ID or Face ID.
  • The user isn’t enrolled in biometrics, or doesn’t have a passcode set.
  • The user cancels the operation.
  • Touch ID or Face ID fails to recognize the user.
  • You’ve previously invalidated the context with a call to the invalidate() method.

For a complete list of possible error conditions, see LAError.Code.

In a real app, if you encounter a local authentication error, fall back to your own authentication scheme, like asking for a username and password. Use biometrics as a supplement to something you’re already doing. Don’t depend on biometrics as your only authentication option.