How to Test Biometric Authentication (Fingerprint, Face, Voice)

Biometric auth is a convenience feature with security implications. Ship it carelessly and you replace a 16-character password with "glance at screen" — which, depending on how you built it, might mea

May 27, 2026 · 4 min read · How-To Guides

Biometric auth is a convenience feature with security implications. Ship it carelessly and you replace a 16-character password with "glance at screen" — which, depending on how you built it, might mean anyone holding the phone can unlock the app. Ship it well and you get genuine friction reduction with no security loss. This guide covers the test plan for doing it well.

What biometric auth actually is

On Android: BiometricPrompt API abstracts fingerprint, face, iris, PIN/pattern, and device-credential fallback. On iOS: LocalAuthentication framework with Touch ID, Face ID, and passcode fallback. In both cases, the biometric sensor verifies identity; a secure enclave (Keystore / Secure Enclave) holds the key material. Your app never sees the biometric data — it gets a cryptographic confirmation.

The common mistake: treating biometric success as "logged in." It is not. Biometric unlocks a local secret (a refresh token, an encrypted key). The server still enforces auth independently.

What to test

Enrollment

  1. User has biometric enrolled in OS — your app detects it
  2. User has no biometric enrolled — your app offers alternative
  3. Multiple fingerprints enrolled — any registered finger unlocks
  4. New biometric enrolled after app setup — app re-prompts for password before trusting new print (biometric change invalidates key)

Happy path

  1. Biometric prompt shown at correct moment
  2. Successful biometric unlock → login
  3. Token retrieved from Keystore, sent to server, session established
  4. Subsequent launches unlock with biometric, no network call until token expires

Failure modes

  1. Wrong biometric (unregistered face) → prompt rejects, retry allowed
  2. Five wrong attempts → biometric disabled temporarily, falls back to password
  3. Biometric hardware unavailable (dirty sensor) → fallback to password offered
  4. Hardware not supported on device → biometric option hidden

Fallback

  1. "Use password instead" button visible
  2. Fallback unlocks without needing biometric
  3. After password fallback, biometric re-enabled on next launch

Security

  1. Biometric change (new face added in OS) — all biometric-bound keys invalidated
  2. Device root/jailbreak detection — biometric refused on compromised device
  3. Biometric does not bypass server-side 2FA where 2FA is required
  4. Screenshot of biometric prompt does not expose app content
  5. Keystore key requires user authentication for every access (not just at enrolment)

Session behavior

  1. Session timeout after N minutes — biometric re-prompt
  2. Force-kill and relaunch — biometric re-prompt
  3. Return from background after > 30 seconds — biometric re-prompt (configurable)
  4. Biometric disabled in app settings — falls back to password flow entirely

UI / UX

  1. Prompt displays app branding / custom message
  2. Prompt respects dark mode
  3. Haptic feedback on success
  4. Loading state during key unwrap (iOS Face ID takes a fraction of a second)
  5. Error messages clear — "fingerprint not recognized" not "authentication failed, code 12"

Accessibility

  1. Non-biometric alternative always available (users with amputation, blindness affecting face recognition)
  2. VoiceOver / TalkBack describes the prompt
  3. Button to skip biometric and use password — accessible and labeled

Manual testing

Use a physical device. Enroll a biometric. Set up your app with biometric unlock. Go through the full matrix:

Automated testing

You cannot automate biometric itself — sensor access is hardware-gated and requires a human finger or face. You can automate the surrounding logic.

Android — use BiometricManager in tests


@Test
fun biometricNotAvailable() {
    val manager = BiometricManager.from(context)
    // Force a state via shadow/mock
    whenever(manager.canAuthenticate(BIOMETRIC_STRONG))
        .thenReturn(BIOMETRIC_ERROR_NONE_ENROLLED)
    // Assert app shows enrollment CTA
}

Instrumented tests on emulators with simulated fingerprint work for the happy path:


adb -e emu finger touch 1

iOS — LocalAuthentication mocking


class MockLAContext: LAContext {
    override func evaluatePolicy(...) { reply(true, nil) }
}
// Inject MockLAContext in test builds

How SUSA handles this

SUSA cannot drive real biometric (no hardware access from test agent). It detects biometric prompts on screen and:

Manual biometric testing stays as a per-release human pass. SUSA automates the surrounding flows.

Common production bugs

  1. Keystore key not invalidated on new biometric enrollment — attacker with physical access enrolls their own fingerprint after stealing phone, unlocks victim's app. Fix: setInvalidatedByBiometricEnrollment(true) in Android Keystore.
  2. Biometric success treated as server auth — backend accepts biometric-success token without checking validity. Fix: server always validates a real auth token, not a biometric flag.
  3. "Remember device" has no expiry — device trusted forever. Fix: 30-90 day expiry with re-auth.
  4. Screenshot blocking missing on biometric screen — balance / sensitive data captured in shot. Fix: FLAG_SECURE or equivalent on sensitive activities.
  5. Face ID without true depth check — photo of user unlocks. Fix: iOS handles this; Android Face Unlock on some vendors does not. Use BIOMETRIC_STRONG class only.

Biometric is worth the investment but worth the test effort. Cutting corners here means either friction (for users) or security (for attackers).

Test Your App Autonomously

Upload your APK or URL. SUSA explores like 10 real users — finds bugs, accessibility violations, and security issues. No scripts.

Try SUSA Free