Biometric Authentication is an extension of fingerprint authentication. The Biometric API is more advanced and simpler to integrate when compared to previous versions. In this article, you will learn how to integrate the Biometric API and how to use it.
I. Introduction
In recent years, the Android development team has focused primarily on improving security and privacy. Pattern / pin lock has been present for many years on Android devices, about a few years ago, fingerprint authentication was introduced as an improvement. And now fingerprint authentication is upgraded and is called biometric authentication. Biometric authentication is safer and easier to use, useful in many situations, such as payment authorizations, secure and simple login, authentication while accessing sensitive data and more. again. In addition, the Biometric API also provides a way to authenticate with device passwords or pin codes without the need for any additional work for developers.
II. Check system compatibility
As I said above, the Android security system starts with a password lock and a pin lock, so some devices don’t have the ability to unlock with a fingerprint or face unlock. Before enabling this type of authentication for users, you should perform a test to see if the device is compatible with biometric authentication. To check availability, we first need to get an instance of the system’s BiometricManager class:
1 2 | val biometricManager = BiometricManager.from(this) |
For the BiometricManager object, we need to access the canAuthenticate () function, the result of this function is an integer and the following 4 results can occur:
- BIOMETRIC_SUCCESS : The device can work with biometric authentication.
- BIOMETRIC_ERROR_NO_HARDWARE : There is no biometric feature available on this device.
- BIOMETRIC_ERROR_HW_UNAVAILABLE : Biometric features are currently not available in the device.
- BIOMETRIC_ERROR_NONE_ENROLLED : The user does not link any biometric information in the device.
Use when in Kotlin to solve different use cases:
1 2 3 4 5 6 7 8 9 10 11 12 13 | private fun verfiyingBioMetricExistence() { when (biometricManager.canAuthenticate()) { BiometricManager.BIOMETRIC_SUCCESS -> "App can authenticate using biometrics.".print() BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> "No biometric features available on this device.".print() BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> "Biometric features are currently unavailable.".print() BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> "The user hasn't associated any biometric credentials with their account.".print() } } |
III. Integrate
Integrating biometric library is not difficult, we need to add the following line in the file build.gradle (app):
1 2 3 4 | dependencies { implementation 'androidx.biometric:biometric:1.0.1' } |
Check out the latest version at https://developer.android.com/training/sign-in/biometric-auth
IV. Works with Biometric Library
This is the most interesting part, let’s embark on the code. First, create an Executor instance:
1 2 | val executor = ContextCompat.getMainExecutor(this) |
The getMainExecutor function returns an Executor object that runs tasks that are processed on the main thread associated with the context. This is the thread used to call application components (activities, services, …). This Executor is used to bridge the gap between your biometric services and your application components.
Next, we need to create an instance of BiometricPrompt as shown below, to prompt the user for authentication. It has three arguments.
- Instance of Android Component (activity / fragment)
- The Executor we created above
- Biometric.AuthenticationCallback
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | biometricPrompt = BiometricPrompt(this, executor, object : BiometricPrompt.AuthenticationCallback() { override fun onAuthenticationError(errorCode: Int, errString: CharSequence) { super.onAuthenticationError(errorCode, errString) Toast.makeText(applicationContext, "Authentication error: $errString", Toast.LENGTH_SHORT) .show() } override fun onAuthenticationSucceeded( result: BiometricPrompt.AuthenticationResult) { super.onAuthenticationSucceeded(result) Toast.makeText(applicationContext, "Authentication succeeded!", Toast.LENGTH_SHORT) .show() } override fun onAuthenticationFailed() { super.onAuthenticationFailed() Toast.makeText(applicationContext, "Authentication failed", Toast.LENGTH_SHORT) .show() } }) |
Now it’s time to post the necessary information on the prompt via PromptInfo Builder:
1 2 3 4 5 | promptInfo = BiometricPrompt.PromptInfo.Builder() .setTitle("Biometric login for my app") .setSubtitle("Log in using your biometric credential") .build() |
We then display the biometric dialog using the authenticate function of BiometricPrompt by sending promptInfo as a parameter:
1 2 | biometricPrompt.authenticate(promptInfo) |
That’s all, the rest of the work will be processed by the biometric API and provided consistent results through Callbacks. To understand it a bit better, take a look at the following code snippet, where all of the above are put together:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | private lateinit var executor: Executor private lateinit var biometricPrompt: BiometricPrompt private lateinit var promptInfo: BiometricPrompt.PromptInfo private fun showBiomertricDialog(){ executor = ContextCompat.getMainExecutor(this) biometricPrompt = BiometricPrompt(this, executor, object : BiometricPrompt.AuthenticationCallback() { override fun onAuthenticationError(errorCode: Int, errString: CharSequence) { super.onAuthenticationError(errorCode, errString) Toast.makeText(applicationContext, "Authentication error: $errString", Toast.LENGTH_SHORT) .show() } override fun onAuthenticationSucceeded( result: BiometricPrompt.AuthenticationResult) { super.onAuthenticationSucceeded(result) Toast.makeText(applicationContext, "Authentication succeeded!", Toast.LENGTH_SHORT) .show() } override fun onAuthenticationFailed() { super.onAuthenticationFailed() Toast.makeText(applicationContext, "Authentication failed", Toast.LENGTH_SHORT) .show() } }) promptInfo = BiometricPrompt.PromptInfo.Builder() .setTitle("Biometric login for my app") .setSubtitle("Log in using your biometric credential") .build() biometricPrompt.authenticate(promptInfo) } |
V. Turn on the option of using a password
There will be times when your fingerprint authentication or facial recognition may be problematic. For example, when there is not enough light to recognize the face it may not work as required. In situations like this, users will be able to use other authentication modes, like pin / password / pattern. To allow that, the Biometric library provides the setDeviceCredentialALLowed () function in the BiometricPrompt.PromptInfo object by passing the parameter true:
1 2 3 4 5 6 7 | promptInfo = BiometricPrompt.PromptInfo.Builder() .setTitle("Biometric login for my app") .setSubtitle("Log in using your biometric credential") // Allows device pin .setDeviceCredentialAllowed(true) .build() |
BECAUSE. References
To read more about security in android, you can refer here: https://medium.com/better-programming/secure-communication-with-the-server-from-your-android-client-with- certificate-pinning-5f53cea55972 https://medium.com/better-programming/how-to-set-up-biometric-authentication-in-android-672688afcaae