Skip to content

Implement Biometric Authentication in the iOS App

Local Authentication Framework

LocalAuthentication

Set the Face ID Usage Description

In any project that uses biometrics, include the NSFaceIDUsageDescription key in your app’s Info.plist file. Otherwise, authorization requests may fail.

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.

XML
<key>NSFaceIDUsageDescription</key>
<string>We use Face ID/Touch ID to enhance the security of your app and protect your personal information.</string>
face-id-usage-description

Create and Configure a LAContext

You perform biometric authentication in your app using an LAContext instance, which brokers interaction between your app and the Secure Enclave.

swift
var context = LAContext()
context.localizedCancelTitle = "Enter Username/Password" // Optional, set a custom message for the Cancel button

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:

swift
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
}

LAPolicy definition:

  • .deviceOwnerAuthenticationWithBiometrics: authenticated using a biometric method (Touch ID or Face ID).
  • .deviceOwnerAuthentication: authenticated by biometry or device passcode.
  • .deviceOwnerAuthenticationWithCompanion(iOS18): authenticated by a companion device e.g. Watch, Mac, etc.
  • .deviceOwnerAuthenticationWithBiometricsOrCompanion(iOS18): authenticated by biometry or a companion device e.g. Watch, Mac, etc.

Evaluate a Policy

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

swift
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.
        // ...
    }
}

The localizedReason is used by Touch ID or passcode authentication. The name of your app already appears before the reason you give, so you don’t need to include that in your message.

Accessing Keychain Items

keychain-localauthentication

swift
let access = SecAccessControlCreateWithFlags(nil, // Use the default allocator.
                                             kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
                                             .userPresence,
                                             nil) // Ignore any error.

The userPresence flag tells keychain services to request biometric authentication, or to fall back on the device passcode, whenever the item is later read from the keychain.

SecAccessControlCreateFlags definition:

  • devicePasscode: access an item with a passcode
  • biometryAny: access an item with Touch ID for any enrolled fingers, or Face ID
  • biometryCurrentSet: access an item with Touch ID for currently enrolled fingers, or from Face ID with the currently enrolled user.
  • userPresence: access an item with either biometry or passcode.

References