Implementing Biometric Authentication
1. Checking Biometric Availability
| Property | Description | Values |
|---|---|---|
| BiometricManager | Class used to check biometric authentication support | BiometricManager |
| canAuthenticate() | Checks if biometric authentication is available | int |
Example: Checking Biometric Availability
import android.hardware.biometrics.BiometricManager
import android.os.Build
val biometricManager = BiometricManager.from(context)
val canAuthenticate = biometricManager.canAuthenticate()
when (canAuthenticate) {
BiometricManager.BIOMETRIC_SUCCESS -> {
// Biometric authentication is available
}
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> {
// No biometric hardware available
}
BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> {
// Biometric hardware is unavailable
}
BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED -> {
// Biometric authentication is not supported
}
BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> {
// No biometrics enrolled
}
}
Note: Requires
android.permission.USE_BIOMETRIC or android.permission.USE_FINGERPRINT depending on Android version.2. Creating BiometricPrompt Instance
Example: Creating BiometricPrompt Instance
import android.hardware.biometrics.BiometricPrompt
import android.os.CancellationSignal
import androidx.fragment.app.Fragment
class BiometricAuthFragment : Fragment() {
private lateinit var biometricPrompt: BiometricPrompt
private lateinit var promptInfo: BiometricPrompt.PromptInfo
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
biometricPrompt = BiometricPrompt(this, object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationSucceeded(
result: BiometricPrompt.AuthenticationResult
) {
// Handle successful authentication
handleSuccessfulAuth()
}
override fun onAuthenticationFailed() {
// Handle failed authentication
handleFailedAuth()
}
override fun onAuthenticationError(
errorCode: Int,
errString: CharSequence
) {
// Handle authentication error
handleError(errorCode, errString)
}
})
promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle("Biometric Authentication")
.setSubtitle("Scan your fingerprint or face")
.setDescription("Use your biometric credentials to authenticate")
.setConfirmationRequired(true)
.setNegativeButtonText("Use Password")
.build()
}
private fun handleSuccessfulAuth() {
// Proceed with authenticated action
}
private fun handleFailedAuth() {
// Retry or show error
}
private fun handleError(errorCode: Int, errString: CharSequence) {
// Handle error appropriately
}
}
| Property | Description | Values |
|---|---|---|
| PromptInfo.Builder().setTitle() | Sets the title of the biometric prompt | String |
| PromptInfo.Builder().setSubtitle() | Sets the subtitle of the biometric prompt | String |
| PromptInfo.Builder().setDescription() | Sets the description of the biometric prompt | String |
| PromptInfo.Builder().setConfirmationRequired() | Indicates whether confirmation is required after authentication | Boolean |
| PromptInfo.Builder().setNegativeButtonText() | Sets the text for the negative button (e.g., "Use Password") | String |
Note: The
BiometricPrompt requires the USE_BIOMETRIC permission in the manifest.Warning: Ensure that the device has enrolled biometrics before attempting to use
BiometricPrompt.3. Configuring Prompt Info
| Property | Description | Values |
|---|---|---|
| title | Title to display in the biometric prompt | "Authenticate to access your account" |
| subtitle | Subtitle to display in the biometric prompt | "Touch fingerprint sensor" |
| description | Description to display in the biometric prompt | "Use your fingerprint to unlock" |
| negativeButton | Text for the negative button (e.g., "Cancel") | "Cancel" |
Example: Setting up Biometric Prompt Info
val promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle("Authenticate to access your account")
.setSubtitle("Touch fingerprint sensor")
.setDescription("Use your fingerprint to unlock")
.setNegativeButtonText("Cancel")
.build()
4. Authenticating Users
| Property | Description | Example |
|---|---|---|
| BiometricManager | Manages biometric authentication capabilities and availability | val manager = BiometricManager.from(context) |
| BiometricPrompt | Handles the authentication flow and user interaction | val prompt = BiometricPrompt(this, executor, callback) |
| PromptInfo | Configuration for the biometric prompt UI | PromptInfo.Builder().setTitle("Sign in").build() |
Example: Basic Biometric Authentication Setup
class MainActivity : AppCompatActivity() {
private lateinit var biometricPrompt: BiometricPrompt
private lateinit var promptInfo: BiometricPrompt.PromptInfo
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val executor = ContextCompat.getMainExecutor(this)
biometricPrompt = BiometricPrompt(this, executor, object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
// Handle successful authentication
Toast.makeText(this@MainActivity, "Authentication successful", Toast.LENGTH_SHORT).show()
}
override fun onAuthenticationFailed() {
// Handle failed authentication
Toast.makeText(this@MainActivity, "Authentication failed", Toast.LENGTH_SHORT).show()
}
})
promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle("Sign in with fingerprint")
.setSubtitle("Use your fingerprint to authenticate")
.setNegativeButtonText("Cancel")
.build()
}
private fun authenticateUser() {
biometricPrompt.authenticate(promptInfo)
}
}
Note: Ensure you have the necessary permissions in your
AndroidManifest.xml: <uses-permission android:name="android.permission.USE_BIOMETRIC" />
Warning: On devices without biometric hardware,
BiometricManager will return BIOMETRIC_ERROR_HW_UNAVAILABLE. Always check capabilities before attempting authentication.
| Status | Availability | Notes |
|---|---|---|
| NEW | Android 6.0+ | Biometric authentication support added in Android 6.0 (API level 23) |
| DEPRECATED | Android 10+ | Legacy BiometricPrompt methods are deprecated in favor of new API |
5. Handling Authentication Results
| Result Type | Description | Properties |
|---|---|---|
| BiometricPrompt.AuthenticationResult | Represents the result of a successful biometric authentication | cryptoObject, authTime |
| BiometricPrompt.AuthenticationCallback | Interface for handling authentication events | onAuthenticationSucceeded(), onAuthenticationFailed(), onAuthenticationError() |
Example: Handling Authentication Success
class AuthenticationCallback : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
val cryptoObject = result.cryptoObject
// Process successful authentication
handleSuccessfulAuth(cryptoObject)
}
override fun onAuthenticationFailed() {
// Handle failed authentication
showFailureMessage()
}
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
// Handle authentication error
handleError(errorCode, errString)
}
}
Note: The
cryptoObject contains the cryptographic information needed to decrypt or verify data.Warning: Always validate the authentication result before proceeding with sensitive operations.
6. Using CryptoObject
| Property | Description | Values |
|---|---|---|
| CryptoObject | Wrapper for cryptographic objects used in biometric authentication | CryptoObject |
Note: The
CryptoObject is used to provide cryptographic context for biometric authentication, ensuring secure handling of sensitive data.
7. Handling Biometric Errors
| Error Code | Description | Handling Recommendation |
|---|---|---|
| BIOMETRIC_ERROR_HW_UNAVAILABLE | Biometric hardware is unavailable | Inform user to check device compatibility or try again later |
| BIOMETRIC_ERROR_UNABLE_TO_PROCESS | Biometric sensor is unable to process the current image | Ask user to reposition finger or clean sensor |
| BIOMETRIC_ERROR_TIMEOUT | Operation timed out waiting for biometric input | Inform user and allow retry after a delay |
| BIOMETRIC_ERROR_NO_BIOMETRICS | No biometric enrolled on the device | Guide user to set up biometrics in system settings |
| BIOMETRIC_ERROR_LOCKOUT | Too many failed attempts; biometric is temporarily locked out | Inform user and suggest waiting or using alternative auth method |
| BIOMETRIC_ERROR_LOCKOUT_PERMANENT | Lockout is permanent due to too many failed attempts | Redirect user to use alternative authentication method or reset |
| BIOMETRIC_ERROR_USER_CANCELED | User canceled the biometric operation | Gracefully exit and allow user to retry if desired |
| BIOMETRIC_ERROR_HW_NOT_PRESENT | Biometric hardware is not present on the device | Inform user that biometric authentication is not supported |
Example: Error Handling in Biometric Prompt
val biometricPrompt = BiometricPrompt(this, ContextCompat.getMainExecutor(this),
object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
when (errorCode) {
BiometricPrompt.ERROR_HW_UNAVAILABLE -> {
// Handle hardware unavailable
Toast.makeText(this@MainActivity, "Biometric hardware not available", Toast.LENGTH_LONG).show()
}
BiometricPrompt.ERROR_LOCKOUT -> {
// Handle lockout
Toast.makeText(this@MainActivity, "Too many failed attempts. Try again later.", Toast.LENGTH_LONG).show()
}
else -> {
// Handle other errors
Toast.makeText(this@MainActivity, "Authentication error: $errString", Toast.LENGTH_LONG).show()
}
}
}
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
// Handle successful authentication
Toast.makeText(this@MainActivity, "Authentication successful", Toast.LENGTH_SHORT).show()
}
override fun onAuthenticationFailed() {
// Handle failed authentication
Toast.makeText(this@MainActivity, "Authentication failed", Toast.LENGTH_SHORT).show()
}
})
8. Supporting Device Credentials
Device credentials provide an alternative to biometric authentication for users who prefer or need to use PINs, patterns, or passwords.
| Property | Description | Values |
|---|---|---|
| DeviceCredential | Represents the device's built-in authentication methods (PIN, Pattern, Password) | DeviceCredential |
| BiometricPrompt | Class for managing biometric authentication flow | BiometricPrompt |
| CryptoObject | Wraps cryptographic objects for secure authentication | CryptoObject |
Example: Using Device Credentials
val promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle("Authenticate with Device Credential")
.setSubtitle("Use your device PIN or password")
.setAllowedAuthenticators(BiometricManager.Authenticators.DEVICE_CREDENTIAL)
.build()
val biometricPrompt = BiometricPrompt(this, object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
// Handle successful authentication
}
override fun onAuthenticationFailed() {
// Handle failed authentication
}
})
biometricPrompt.authenticate(promptInfo)
Note: Device credentials are supported on Android 10 (API level 29) and higher.
Key Points
- Device credentials provide a fallback for biometric authentication.
- Use
BiometricManager.Authenticators.DEVICE_CREDENTIALto enable device credential support. - Users can authenticate using PIN, pattern, or password.
9. Implementing Biometric Enrollment
Biometric enrollment in Android involves registering a user's biometric credentials (fingerprint, face, etc.) for future authentication. The process typically involves using the BiometricPrompt API to guide users through enrollment.
Example: Starting Biometric Enrollment
import androidx.biometric.BiometricManager
import androidx.biometric.BiometricPrompt
import android.content.Context
import android.os.CancellationSignal
class BiometricEnrollmentHelper(private val context: Context) {
fun startEnrollment() {
val biometricManager = BiometricManager.from(context)
val enrollmentStatus = biometricManager.canAuthenticate()
when (enrollmentStatus) {
BiometricManager.BIOMETRIC_SUCCESS -> {
// Start enrollment process
val promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle("Enroll Fingerprint")
.setSubtitle("Scan your fingerprint to enroll")
.setConfirmationRequired(false)
.build()
val biometricPrompt = BiometricPrompt(this, object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
// Enrollment successful
}
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
// Handle error
}
})
biometricPrompt.authenticate(promptInfo, CancellationSignal())
}
else -> {
// Handle unsupported or unavailable biometric
}
}
}
}
| Property | Description | Notes |
|---|---|---|
| canAuthenticate() | Checks if biometric authentication is available | Returns BIOMETRIC_SUCCESS if ready for enrollment |
| PromptInfo.Builder() | Builds configuration for the biometric prompt | Allows setting title, subtitle, and confirmation settings |
| setConfirmationRequired(false) | Controls whether confirmation is needed after enrollment | Set to false for enrollment flow |
Note: Enrollment requires appropriate permissions in
AndroidManifest.xml, including USE_FINGERPRINT or USE_BIOMETRIC.
Warning: Users must explicitly consent to biometric enrollment. Do not proceed without user interaction.
10. Testing Biometric Authentication
Example: Testing Biometric Authentication Flow
class BiometricAuthTest {
@Test
fun testBiometricAuthenticationSuccess() {
val activity = Robolectric.buildActivity(MainActivity::class.java).create().get()
val biometricPrompt = BiometricPrompt.Builder(activity)
.setTitle("Authenticate")
.setSubtitle("Scan your fingerprint")
.setDescription("Touch sensor to authenticate")
.build()
val callback = object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationSucceeded(
result: BiometricPrompt.AuthenticationResult
) {
assertTrue("Authentication should succeed", true)
}
override fun onAuthenticationFailed() {
fail("Authentication failed unexpectedly")
}
}
biometricPrompt.authenticate(
CancellationSignal(),
ContextCompat.getMainExecutor(activity),
callback
)
}
}
| Test Case | Description | Status |
|---|---|---|
| Successful Authentication | Simulates successful biometric scan with valid credentials | NEW |
| Failed Authentication | Simulates failed biometric scan with invalid credentials | NEW |
| Device Not Supported | Verifies behavior when device lacks biometric hardware | LEGACY |
Note: Ensure that your testing environment has appropriate biometric simulation enabled.
Warning: Do not use real biometric data in automated tests; always simulate or mock.