Mobile Biometric Authentication: What to Verify
Biometric authentication is local user verification, not remote identity proof. Android and Apple keep biometric templates outside app access: app receives a success or failure result. That boundary matters. A green biometric prompt must not become permission to reuse an old server session, approve a different transaction, or silently reveal a protected secret.
This review asks a narrower question: what cryptographic operation becomes possible after local authentication, for how long, and through which fallback? OWASP MASVS identifies bypassable local authentication, weak fallback, missing step-up authentication, and missing invalidation after biometric enrollment as distinct failure classes.
Start with protected operation
Write one row per operation before reading code. “Use Face ID” is not a requirement; “sign this server challenge before changing a beneficiary” is.
| Operation | Required local proof | Server control | Evidence owner | Pass condition |
|---|---|---|---|---|
| Open cached account data | device credential may be acceptable | valid session still required | mobile owner | app cannot decrypt before prompt succeeds |
| Approve payment | strong biometric, fresh prompt | server verifies challenge, amount, recipient, expiry | payment owner | changed amount invalidates approval |
| Export recovery material | no local-only shortcut | reauthentication and policy decision | identity owner | fallback cannot weaken transaction policy |
Keep challenge data scoped: include action, account, transaction identifier, expiry, and nonce. Never sign a generic “approved” string. Server must reject replayed, expired, or action-mismatched proof.
Bind prompt to key use
A visual prompt alone is weak evidence because an app can show it then use a previously available key or token. Bind authentication to the private-key operation or protected Keychain item. Android supports passing a CryptoObject to BiometricPrompt; generate a Keystore key requiring user authentication, then use its initialized cipher or signature only after prompt success. Example shape:
val spec = KeyGenParameterSpec.Builder(alias, PURPOSE_SIGN)
.setUserAuthenticationRequired(true)
.setUserAuthenticationParameters(0, AUTH_BIOMETRIC_STRONG)
.setInvalidatedByBiometricEnrollment(true)
.build()
// authenticate(promptInfo, BiometricPrompt.CryptoObject(signature))
0 means per-use authentication in this example. Check actual supported API levels and authenticator combinations; do not copy settings into a production policy without device testing. On iOS, LAContext evaluates a policy, while Keychain access control can require current biometry for a protected item. The secret or private key must remain protected by platform storage; do not replace this with an app-managed biometric flag.
Apple documents that LocalAuthentication returns a Boolean result and does not expose fingerprint or facial data. Android authenticator selection matters too: BIOMETRIC_STRONG and device credential are different policy choices. Choose them per operation, record reason, and test device support before release.
Fallback is policy, not error handling
Fallback happens when biometrics are unavailable, unenrolled, locked out, cancelled, or deliberately disabled. Device PIN/passcode can be a usable fallback for low-risk local unlock, but it changes assurance. A support PIN embedded in app UI, a remembered password, or “continue anyway” is not an equivalent fallback.
Define expected behavior for every outcome:
| Outcome | Expected behavior | Fail signal | Remediation |
|---|---|---|---|
| biometric success | perform bound operation once | operation succeeds without bound object | recreate protected key and retest |
| user cancel | stop with no state change | request proceeds after cancellation | separate cancel from success callback |
| lockout / unavailable | offer approved recovery or stop | app silently downgrades | require explicit server reauthentication |
| device credential fallback | only where risk owner approved it | high-risk action accepts it | remove fallback for that action |
| enrollment changed | invalidate or re-establish protected material | old key still works unexpectedly | rotate key and require sign-in |
Do not treat biometric failure as an authorization decision. Local authentication can unlock a key; server-side authorization still checks session state, account permissions, action limits, and transaction freshness.
Test evidence and release gate
Owner: mobile security owner records device model, OS version, authenticator policy, and test result. Feature owner records risk decision for fallback. Backend owner records challenge validation. Evidence includes source excerpts, signed build identifier, screen capture of prompt path, and test traces showing no signature or decryption after cancel, lockout, enrollment change, or expired challenge.
Pass when every protected action uses deliberate authenticators, cryptographic binding where key material matters, defined fallback, and server-side replay protection. Fail when a success Boolean alone gates action, fallback is undocumented, protected data remains readable after termination, or changing biometric enrollment leaves sensitive key use intact. Exception: an accessibility or device-support constraint may use device credential only when risk owner documents scope, compensating server controls, expiry, and review date. Remediate by narrowing action, requiring fresh server authentication, rotating keys, then rerunning failure-path tests.
Mobile application penetration testing can inspect the built app and device behavior; it does not replace product approval of transaction risk.
Worked case: beneficiary change
A tester starts an authenticated session, opens a beneficiary-change screen, then invokes the biometric prompt. Capture request bytes before confirmation. Expected output is a one-use server challenge whose signed payload names beneficiary identifier, destination account, operation, expiry, and nonce. Change one destination digit after prompt display and submit original proof. Server should reject it because signed context no longer matches requested change. Repeat after cancellation, biometric lockout, and enrollment modification. Closure evidence is device trace plus server rejection record for each path, keyed only by test run identifier. This test distinguishes prompt presentation from cryptographic authorization.
Edge tests before closure
Attempt to reuse a valid signature, restore app from background, and submit after challenge expiry. Check no pending mutation appears after each rejected request. Test supported device-credential path separately; report its policy decision rather than calling it biometric equivalent. Retest released build, record app version and backend validation version, then close only when failure outputs contain no state change and success output changes exactly requested beneficiary.