Android Biometric API primer
It's quite probable that your app handles at least some "sensitive" data. It might be the case that the only sensitive data are just the app settings, or it might be the case that the entire app is sensitive (e.g. banking apps). Either way, it's quite common that you might need to secure the app (or just a screen within the app) with some kind of authentication.
No need to implement your own logic and hassle with storing and verifying credentials though. Android provides an easy mechanism to authenticate the user using the existing device methods (e.g. fingerprint, device password, etc). The user won't have to create yet another user/pass combination and a familiar trusted system UI will be used for the authentication.
Without further ado, let's get a taste of how we can authenticate the user using the AndroidX Biometric Library. This is a library that allows uniform access to the biometric hardware to all the devices running Android 6.0 (API level 23) and above.
Install the library
Add the dependency to your build.gradle
. As always, check for the latest version.
implementation "androidx.biometric:biometric:1.1.0"
Show the authentication
override fun onCreate(savedInstanceState: Bundle?) {
[...]
val biometricManager = BiometricManager.from(this)
if (biometricManager.canAuthenticate( // 1.
BIOMETRIC_WEAK or DEVICE_CREDENTIAL) == BIOMETRIC_SUCCESS) {
instanceOfBiometricPrompt().authenticate(getPromptInfo())
}
}
private fun instanceOfBiometricPrompt(): BiometricPrompt {
val executor = ContextCompat.getMainExecutor(this) // 2.
val callback = object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationSucceeded(
result: BiometricPrompt.AuthenticationResult) {
// 3.
}
override fun onAuthenticationFailed() {
// 4.
}
override fun onAuthenticationError(errorCode: Int,
errString: CharSequence) {
// 5.
}
}
return BiometricPrompt(this, executor, callback)
}
private fun getPromptInfo(): BiometricPrompt.PromptInfo = // 6.
BiometricPrompt.PromptInfo.Builder()
.setTitle("Prompt title")
.setSubtitle("Prompt subtitle")
.setDescription("Prompt description")
.setAllowedAuthenticators(
BIOMETRIC_WEAK or DEVICE_CREDENTIAL) // 7.
.build()
- Firstly, check that the device can authenticate using the desired methods.
BIOMETRIC_WEAK
means that you want authentication just for accessing a part of the app (without doing anything cryptographically).DEVICE_CREDENTIAL
means you allow the user to authenticate using the device password/passcode.
The resultingBIOMETRIC_SUCCESS
is the "happy path". Check the rest of the enum values to handle the cases where the requested authentication methods are not available or not set. For instance, if the user has fingerprint hardware, but didn't set it up, there's a way to prompt that user to set it up if you want. - The prompt needs to run in the main UI thread. This is an easy way to get that thread across every Android version.
- Handle here what happens when the user successfully authenticates (e.g. proceed with accessing the app / restricted screen). Check the
result
object to check which of the allowed authentication methods was used, if needed. - Called when the user failed to authenticate, but can still try again (e.g. placed an unrecognized finger on the sensor).
- Called when an unrecoverable error has occurred.
- All the metadata that will be shown in the prompt. The system prompt will look like the one below.
- The allowed authentication methods should be the same as in step 1 ideally. Note here that if the authentication methods are invalid or unsupported on the current device a runtime error will be thrown on
build()
. So always use step 1 to check that the combination is valid and supported.
Hopefully, you got a taste of how to authenticate and protect sensitive parts of your app using Android's Biometric API.
Happy coding!