Implementing Biometric Authentication (Touch ID/Face ID)

Table of Contents
Big thanks to our contributors those make our blogs possible.

Our growing community of contributors bring their unique insights from around the world to power our blog. 

Introduction

Biometric authentication—using fingerprints (Touch ID) or facial recognition (Face ID)—adds a seamless, secure layer to user login and sensitive operations in mobile apps. By leveraging the device’s built-in sensors and secure enclave, you eliminate cumbersome passwords while maintaining strong protections against unauthorized access. In this guide, you’ll learn why biometrics matter, how to integrate Touch ID and Face ID on iOS, and how to implement fingerprint and facial unlock on Android. You’ll also discover best practices for user experience, fallback strategies, and troubleshooting common pitfalls, ensuring your app delivers both security and convenience.

Why Biometric Authentication Matters

  • Enhanced Security: Biometric data is stored in a hardware-backed secure enclave, never exposed to the app layer or server.
  • Frictionless UX: One-tap authentication replaces lengthy password entry, reducing drop-offs in signup or payment flows.
  • Regulatory Compliance: Many data-sensitive industries (finance, healthcare) recommend or require multi-factor authentication—biometrics can serve as a second factor.
  • User Trust: Familiar system prompts reassure users that you’re using platform-provided security rather than rolling your own.

Expert Insight: According to a 2023 survey by Duo Security, use of biometric authentication on mobile apps has increased user adoption by 30% and reduced account recovery requests by 45%.

High-Level Workflow

  1. Check Biometric Capability: Determine if device supports Touch ID, Face ID (iOS), or biometric modalities (Android).
  2. Request Consent: Trigger the system prompt to enroll or authenticate using biometrics.
  3. Handle Callbacks: Process success or failure, and fall back to PIN/password if needed.
  4. Secure Storage: Tie biometric success to unlocking credentials stored in the secure enclave or keystore.

iOS Implementation with LocalAuthentication

1. Import and Context Setup

swiftCopyEditimport LocalAuthentication

let context = LAContext()
var authError: NSError?

2. Check Availability

swiftCopyEditif context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &authError) {
    let type = context.biometryType == .faceID ? "Face ID" : "Touch ID"
    print("\(type) is available.")
} else {
    print("Biometrics not available: \(authError?.localizedDescription ?? "Unknown error")")
}

3. Perform Authentication

swiftCopyEditlet reason = "Authenticate to access your secure data"
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { success, error in
    DispatchQueue.main.async {
        if success {
            // Unlock sensitive data or proceed
            self.showSecureContent()
        } else {
            // Fall back to passcode or show error
            self.promptForPassword()
        }
    }
}

4. Secure Credential Storage

Use Keychain with kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly linked to biometric policy:

swiftCopyEditlet access =
    SecAccessControlCreateWithFlags(nil,
                                   kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
                                   .userPresence,
                                   nil)!
let attributes: [String: Any] = [
    kSecClass as String: kSecClassGenericPassword,
    kSecAttrAccount as String: "userToken",
    kSecValueData as String: tokenData,
    kSecAttrAccessControl as String: access
]
SecItemAdd(attributes as CFDictionary, nil)

On retrieval, the system will prompt the user’s biometric before returning the item.

Android Implementation with BiometricPrompt

1. Add Dependencies

gradleCopyEditimplementation "androidx.biometric:biometric:1.2.0"

2. Create BiometricPrompt Instance

kotlinCopyEditval executor = ContextCompat.getMainExecutor(context)
val biometricPrompt = BiometricPrompt(this, executor,
    object : BiometricPrompt.AuthenticationCallback() {
        override fun onAuthenticationSucceeded(
           result: BiometricPrompt.AuthenticationResult
        ) {
           showSecureContent()
        }
        override fun onAuthenticationError(
           errorCode: Int, errString: CharSequence
        ) {
           promptForPin()
        }
    })

3. Build Prompt Info

kotlinCopyEditval promptInfo = BiometricPrompt.PromptInfo.Builder()
    .setTitle("Biometric login")
    .setSubtitle("Use your fingerprint or face to continue")
    .setNegativeButtonText("Use PIN")
    .build()

4. Trigger Authentication

kotlinCopyEditif (BiometricManager.from(context)
.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG
or BiometricManager.Authenticators.DEVICE_CREDENTIAL)
== BiometricManager.BIOMETRIC_SUCCESS) {
biometricPrompt.authenticate(promptInfo)
} else {
promptForPin()
}

5. Secure Key Storage

Use Android Keystore to generate an encryption key tied to biometric authentication:

kotlinCopyEditval keyGen = KeyGenerator.getInstance(
    KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore"
)
val spec = KeyGenParameterSpec.Builder(
    "biometricKey",
    KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
)
    .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
    .setUserAuthenticationRequired(true)
    .setUserAuthenticationValidityDurationSeconds(-1) // require each time
    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
    .build()
keyGen.init(spec)
keyGen.generateKey()

Attempting to use this key invokes the biometric prompt, ensuring only authenticated users can decrypt stored data.

Best Practices

  • Graceful Fallbacks: Always offer PIN/password fallback (deviceOwnerAuthentication) for users without biometric setup.
  • Privacy Prompts: Explain why you require biometric auth before invoking evaluatePolicy or authenticate—opt-in transparency builds trust.
  • Limited Retry Attempts: Avoid infinite retries; respect system-defined lockouts to prevent brute-force attacks.
  • Session Management: After successful biometric unlock, limit the time window for re-use (e.g., re-prompt after backgrounding the app).
  • Accessibility Considerations: Ensure visually impaired or mobility-challenged users have alternative flows.

Expert Tip: On iOS, monitor context.biometryType to adapt your UI—use a face icon for Face ID, a fingerprint icon for Touch ID, and a generic lock otherwise.

Troubleshooting Common Issues

IssueResolution
User Cancels PromptTreat as authentication failure; fallback to PIN/password.
Biometry Not EnrolledDetect with canEvaluatePolicy, then guide user to Settings to enroll.
Lockout After Too Many AttemptsOn iOS, call .deviceOwnerAuthentication to fallback to passcode.
Legacy Devices (no Biometric Support)Offer deviceOwnerAuthentication or password-only flow.
Keystore/Keychain Access ErrorsEnsure correct accessControl flags and handle exceptions with logging.

Conclusion

Implementing biometric authentication elevates both security and user experience by leveraging device-native fingerprint and facial recognition. On iOS, the LocalAuthentication framework combined with Keychain Access Control offers a robust solution; on Android, BiometricPrompt and the Keystore API deliver equivalent protection. By following best practices—such as clear user consent, fallback options, secure key storage, and careful session management—you’ll provide a seamless, trustworthy unlock flow that users love and security standards demand. Start integrating biometrics today to make your app more secure, user-friendly, and compliant with modern authentication expectations.

Let's connect on TikTok

Join our newsletter to stay updated

Sydney Based Software Solutions Professional who is crafting exceptional systems and applications to solve a diverse range of problems for the past 10 years.

Share the Post

Related Posts