In-App Authentication Made Easy With Biometric API
Tags: android, authentication, security, mobile
Published: 2023-07-03 09:14:30

In Android Apps nowadays, there are various forms of user authentication we get to implement such as login, verification, transaction approval and so on. Traditionally, we would authenticate users with emails, passwords, OTP and the like but what if we can authenticate a user with the security token they already use on their device such as fingerprints, face, iris, password, PIN, or pattern?

With the release of Android 10 (API level 29), a new Biometric API was introduced to help Android developers seamlessly authenticate their users with Biometrics or device credentials (password, PIN, or pattern) already registered on the device. This feature is also backwards compatible, down to Android 6 (API level 23). Integrating this library is pretty straightforward and can be done in 4 simple steps.

NB: This article is also available on [Medium](https://olugbohunmijoseph.medium.com/in-app-authentication-made-easy-with-biometric-api-b603b8e26324)

**_Now the four simple steps…_**

**Step 1: Add the dependency**
In the App's `build.gradle` file, add the dependency to download the library's artifacts.

```
dependencies {
    ...
    implementation "androidx.biometric:biometric:${current_version}"
}
```
At the time of writing this article, the version was `1.1.0`

**Step 2: Check if the device can perform Biometric Authentication**
Do this check in `onCreate()` of your Activity or `onViewCreated()` of your Fragment.

```
private fun canAuthenticate(): Boolean {
    val biometricManager = BiometricManager.from(requireContext())
    return biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_WEAK) == BiometricManager.BIOMETRIC_SUCCESS
}

if (canAuthenticate()) {
  // initializeBiometricAuth()
}
```
Before now, we could just use `biometricManager.canAuthenticate()` but that has been deprecated for the one mentioned above where we have to pass in a type of Authenticator.

**Step 3: Instantiate BiometricPrompt and build PromptInfo**

```
private fun initializeBiometricAuth() {
        val executor: Executor = ContextCompat.getMainExecutor(context)

        val authCallback = object : BiometricPrompt.AuthenticationCallback() {

            override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
                super.onAuthenticationSucceeded(result)
                showToast("Success!")
                // proceed
            }

            override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
                super.onAuthenticationError(errorCode, errString)
                showToast("Error occurred: $errString")
            }

            override fun onAuthenticationFailed() {
                super.onAuthenticationFailed()
                showToast("Authentication failure")
            }
        }

        val biometricPrompt = BiometricPrompt(this, executor, authCallback)

        val promptInfo: BiometricPrompt.PromptInfo = BiometricPrompt.PromptInfo.Builder()
            .setTitle("Authentication")
            .setSubtitle("Subtitle")
            .setDescription("Short description")
            .setNegativeButtonText("Cancel")
            .setConfirmationRequired(true)
            .setAllowedAuthenticators(BiometricManager.Authenticators.DEVICE_CREDENTIAL)
            .build()
}
```
BiometricPrompt can be  constructed using 3 parameters; the context, an Executor and the AuthenticationCallback. `AuthenticationCallback` is an abstract class that has 3 methods; `onAuthenticationError()` - called when an error occurs, `onAuthenticationSucceeded()` - called when authentication is successful and `onAuthenticationFailed()` - called when authentication failed. Any of these methods can be implemented based on your requirements, but of course, `onAuthenticationSucceeded()` is very important.

While building BiometricPrompt.PromptInfo, you can provide any relevant information such as title, subtitle, description, and so on. Before now, we could just call `setDeviceCredentialAllowed(true)` but that has been deprecated for `setAllowedAuthenticators()` mentioned above. This method makes it possible to authenticate using a password, PIN, or pattern. **Please note that when `setAllowedAuthenticators(DEVICE_CREDENTIAL)` is called, you cannot also call `setNegativeButtonText()`**.

**Step 4: Authenticate the User**
Finally, you can call the authenticate method, passing in the PromptInfo object to authenticate the user.

```
biometricPrompt.authenticate(promptInfo)
```
This will display a Dialog with the provided information, now you can seamlessly authenticate a user in your App.

The Biometric API can also be used to perform other cryptographic operations. For advanced topics relating to the Biometric API, you can have a look at the [official documentation](https://developer.android.com/jetpack/androidx/releases/biometric).

Thanks for reading! If you have any observations, kindly share your thoughts in the comment section. You can also reach out to me via [Twitter](https://twitter.com/mayorjay1) or [LinkedIn](https://www.linkedin.com/in/joseph-olugbohunmi/).