BiometricDeviceCredentialAuthenticator

public class BiometricDeviceCredentialAuthenticator : DefaultDeviceAuthenticator

An authenticator that uses biometrics (Face ID or Touch ID) with a fallback to device credentials (passcode/PIN).

This authenticator supports the BIOMETRIC_ALLOW_FALLBACK policy, allowing authentication via either biometrics (Face ID / Touch ID) or device passcode.

Security Model

Unlike BiometricOnlyAuthenticator which uses .biometryCurrentSet to have the Secure Enclave hardware-invalidate keys when biometric enrollment changes, this class uses a dynamic access control policy:

  • Biometrics enrolled: .biometryAny OR .devicePasscode — allows both authentication methods.
  • No biometrics enrolled: .devicePasscode only — avoids Secure Enclave key creation failure on devices that have a passcode set but no Face ID / Touch ID registered.

Because .biometryAny does not invalidate keys on biometric enrollment changes at the hardware level, this class compensates with a software-level check using LAContext.evaluatedPolicyDomainState. The biometric domain state is captured at bind time and stored in the UserKey. During signing, the stored state is compared against the current state — if they differ (e.g., a fingerprint was added or removed), the keys are deleted and re-binding is required by throwing .deviceNotRegistered.

Backward Compatibility

For UserKey instances created before this change (i.e., without a stored biometricDomainState), the enrollment check is skipped and signing proceeds normally. This ensures existing bindings are not broken on SDK update. Only keys created after the update will enforce the biometric domain state check.

  • Initializes the authenticator with a BiometricAuthenticatorConfig.

    Declaration

    Swift

    public init(config: BiometricAuthenticatorConfig)

    Parameters

    config

    The configuration object for the authenticator.

  • The type of authenticator, specifically .biometricAllowFallback.

    Declaration

    Swift

    public override func type() -> DeviceBindingAuthenticationType
  • register() Asynchronous

    Generates a new cryptographic key pair for biometric and device credential authentication. The key is stored in the Secure Enclave (if available) and associated with a unique key tag.

    Access control flags are dynamically selected based on biometric availability:

    • When biometrics are enrolled: .biometryAny OR .devicePasscode — allows both methods.
    • When only passcode is set: .devicePasscode only — avoids Secure Enclave rejecting key creation when biometry flags are present but no biometrics are enrolled.

    Throws

    DeviceBindingError.unknown if access control creation fails, or a CryptoKey error if key generation fails.

    Declaration

    Swift

    public override func register() async throws -> KeyPair

    Return Value

    A KeyPair containing the newly generated public and private keys.

  • authenticate(keyTag:) Asynchronous

    Declaration

    Swift

    public override func authenticate(keyTag: String) async -> Result<SecKey, Error>

    Return Value

    A Result containing the SecKey on success, or an Error on failure.

  • Checks if the device supports biometric or device credential authentication.

    Note

    Always returns false on simulator — biometric keys require Secure Enclave to enforce the authentication challenge. Without it the key is accessible with no user verification, which is equivalent to the NONE type.

    Declaration

    Swift

    public override func isSupported(attestation: Attestation) -> Bool

    Parameters

    attestation

    The attestation type (currently ignored).

    Return Value

    true if the device supports the authentication policy, false otherwise.

  • deleteKeys() Asynchronous

    Deletes all biometric and device credential keys associated with this authenticator. It iterates through all stored user keys and deletes those with .biometricOnly or .biometricAllowFallback authentication types.

    Throws

    CryptoKeyError if key deletion fails.

    Declaration

    Swift

    public override func deleteKeys() async throws
  • Returns the current biometric domain state from LAContext. Used to detect biometric enrollment changes between bind and sign operations.

    Declaration

    Swift

    public func biometricDomainState() -> Data?

    Return Value

    The evaluated policy domain state data, or nil if biometrics are not enrolled.

  • Override sign to validate biometric enrollment has not changed since binding. If biometrics were enrolled at bind time and the enrollment has since changed, the keys are deleted and .deviceNotRegistered is thrown to trigger re-binding.

    Declaration

    Swift

    public override func sign(params: UserKeySigningParameters, journey: Journey?) throws -> String