Technical guide

Android biometric attributes implementation guide

Implement Android biometric checks with Class 3 keys, key attestation at registration, fresh server challenges, tested recovery and a minimal evidence record.

  • Separate trust decisions

    Local authentication, key use and server authorisation answer different questions. Record the evidence for each.

  • Bind the operation

    Sign a fresh server challenge tied to the account and the intended action with a key that only a Class 3 biometric unlocks.

  • Design safe recovery

    Test unavailable sensors, changed enrolment and lost credentials without treating legitimate users as attackers.

Implement Android biometric attributes as narrowly scoped authentication context, not as a fingerprint of the person. Decide which authenticators each action accepts, check availability, and for anything a server must trust, unlock a Keystore key with a Class 3 (BIOMETRIC_STRONG) biometric through a CryptoObject. Verify that key once with key attestation when you register it, then have it sign a fresh, operation-specific challenge your server checks. A local success callback is never enough for a server to authorise a transaction. Test cancellation, missing hardware, changed enrolment and recovery alongside success. This guide covers Android only.

Define what the biometric result proves

Android grades authenticators. Class 3 (BIOMETRIC_STRONG) biometrics meet the highest security bar and can unlock Keystore keys. Class 2 (BIOMETRIC_WEAK) biometrics can confirm presence but cannot be used with a CryptoObject. DEVICE_CREDENTIAL is the screen-lock PIN, pattern or password. The app declares which of these it accepts with setAllowedAuthenticators() and checks them with BiometricManager.canAuthenticate().

The app never receives biometric data. Android performs the match in its secure environment and returns only a result.

Establish the Android scope

  1. List the device models, Android releases, package variants and signing channels you serve. Record the androidx.biometric version and any framework bridge.
  2. Name the protected action: reopening a local screen, decrypting local data or approving a server transaction. Each needs a different level of proof.
  3. Choose the accepted authenticators for that action. Some combinations, such as BIOMETRIC_STRONG | DEVICE_CREDENTIAL, are not supported on older releases, so call canAuthenticate() with the exact combination you will pass to the prompt.
  4. Keep availability, prompt result, key operation and server decision as separate entries in your test record. An unavailable sensor is not a failed authentication.
ObservationWhat it meansWhat it does not mean
canAuthenticate() returns successThe device can attempt the chosen authenticatorsAnyone has authenticated
Prompt reports successLocal authentication completed under the chosen policyThe server received a fresh approval
getAuthenticationType() reports biometric or device credentialWhich route the user tookThat the route meets the action’s policy
A CryptoObject key operation succeedsA Class 3 biometric unlocked that key for this operationA legal identity or an unmodified app
Server accepts the signed challengeYour verifier accepted this request and credentialApproval of any other operation

Otukan protects Android biometric flows against runtime manipulation, including hooking of the biometric callback. It ties approval to a Keystore key that the platform unlocks only after a successful match. For product scope, see biometric flow protection.

Register the key and verify fresh requests

Create and attest the key

Generate an asymmetric key pair in the Android Keystore with KeyGenParameterSpec:

  • setUserAuthenticationRequired(true) and, on Android 11 or higher, setUserAuthenticationParameters(0, KeyProperties.AUTH_BIOMETRIC_STRONG), so every use needs a fresh Class 3 authentication.
  • setInvalidatedByBiometricEnrollment(true), so adding a new fingerprint or face makes the key unusable.
  • setAttestationChallenge() with a one-time value from your server.
  • setIsStrongBoxBacked(true) where the device has StrongBox and your policy wants it.

Send the public key and its attestation certificate chain to the server. Key attestation is how the server knows the key really lives in secure hardware and is bound to biometric use. The server should:

  1. Verify the chain up to a Google attestation root, and check each certificate against Google’s revocation status list.
  2. Confirm the attestation challenge matches the value it issued.
  3. Read the key description extension: the attestation security level (TrustedEnvironment or StrongBox), the user-authentication requirements and the root of trust, including verified boot state.
  4. Check the attestation application ID: your package name and the digest of your signing certificate.
  5. Store the public key against the account and device registration, with a way to revoke it.

Register only after the account has authenticated through your approved enrolment flow.

Approve an operation

  1. Issue a challenge. The backend creates an unpredictable, single-use challenge tied to the session, the action and its details, with a short expiry.
  2. Check availability. Call canAuthenticate(BIOMETRIC_STRONG) immediately before prompting.
  3. Unlock the key. Initialise a Signature with the private key, wrap it in a BiometricPrompt.CryptoObject and pass it to authenticate().
  4. Sign. In onAuthenticationSucceeded(), use the Signature returned in the result to sign the challenge and the action details. Never substitute a success flag for this signature.
  5. Verify and consume atomically. The backend checks the signature against the registered key, the challenge, the action binding, the expiry and the account state before applying the transaction, and rejects a second use of the same challenge.

With Otukan, your server verifies a signature over a one-time challenge rather than a success flag.

Test both sides of the boundary

Run a legitimate approval first and keep a redacted record of the challenge, the local outcome and the server decision. Then replay the signed challenge, change the amount or payee, switch the account and submit after expiry. Each should be rejected without locking the legitimate user out.

In an authorised lab, tamper with the app’s callback handling. Record whether the protected flow raises the expected signal, and confirm the backend still rejects a request without a valid signature.

Repeat with cancellation, lockout, backgrounding, concurrent prompts and network loss after local approval. Resolve an uncertain transaction by checking server state before retrying; never ask the user to approve a second transaction because the first response was lost.

Minimise data and manage credential changes

Keep outcome categories and the minimum correlation needed for support. Restrict access to the credential registry and set separate retention periods for security evidence and operational logs.

When a user enrols a new biometric, an invalidated key throws KeyPermanentlyInvalidatedException. Treat that as a credential lifecycle event, not as fraud. Otukan supports keys that stop working on new enrolment, with a step-up you define to re-establish trust. Recovery should go through your account verification path before a new key is registered.

  • Reinstall and reset do not restore authority from a stale local flag.
  • New enrolment, removed enrolment and screen-lock changes lead to the documented recovery.
  • Rotation retires old keys under a deliberate transition policy.
  • Revocation blocks further approvals even if a local session remains open.
  • Users without suitable hardware, or with accessibility needs, have another route.
  • Logs contain no reusable signature, challenge or session secret.

For every run, record device, OS, app build, signing channel, configuration, expected outcome, observed outcome and reviewer. Keep clean-device controls alongside adverse cases. Wider platform context is covered on Android app security, and the iOS implementation is covered on the iOS biometric attributes guide.

Further reading

Common questions

  • Which Android biometrics can unlock a Keystore key?

    Only Class 3 (BIOMETRIC_STRONG) biometrics. Class 2 (BIOMETRIC_WEAK) biometrics can confirm presence but cannot be used with a CryptoObject, and DEVICE_CREDENTIAL is the screen-lock PIN, pattern or password. Declare what each action accepts with setAllowedAuthenticators() and check it with BiometricManager.canAuthenticate().

  • Is onAuthenticationSucceeded() enough for the server to approve a transaction?

    No. A local success callback is never enough for a server to authorise a transaction. In onAuthenticationSucceeded(), use the Signature returned in the result to sign a fresh, single-use challenge and the action details. The backend verifies the signature against the registered key and rejects a second use of the challenge.

  • What should the server check in an Android key attestation?

    Verify the chain up to a Google attestation root and against Google's revocation status list, and confirm the attestation challenge matches. Then read the security level, user-authentication requirements and root of trust, including verified boot state, and check the attestation application ID: your package name and signing certificate digest.

  • What happens when a user enrols a new fingerprint or face on Android?

    A key created with setInvalidatedByBiometricEnrollment(true) becomes unusable and throws KeyPermanentlyInvalidatedException. Treat that as a credential lifecycle event, not as fraud. Otukan supports keys that stop working on new enrolment, with a step-up you define, and recovery goes through your account verification path before a new key is registered.

  • What does Otukan add to an Android biometric flow?

    Otukan protects Android biometric flows against runtime manipulation, including hooking of the biometric callback. It ties approval to a Keystore key that the platform unlocks only after a successful match, and your server verifies a signature over a one-time challenge rather than a success flag. The app never receives biometric data.

Verify your biometric trust boundary

Tell us your Android device range, framework and biometric transaction requirement. Do not send binaries, biometric data, signing keys, credentials or production records.

Or request a technical demo