Android Development
Technology, Information and Media
Article

Biometric authentication in Android: A primer

by
Subir Chakraborty
September 7, 2022
4
min(s)
How would the future look if app developers only focused on making sure apps were aesthetically pleasing and fun to use, without complete regard for app security?

ANARCHIC!

Hence, it is crucial for developers to also focus carefully on enhancing app security along with user productivity. One of the most secure manners of boosting app security and safeguarding user data is with the help of biometric authentication, such as facial or fingerprint recognition

Biometric authentication with AndroidX Biometric API

Biometric authentication allows users to unlock their mobile devices using fingerprint or facial recognition. This helps in ensuring that the right person is accessing the mobile device. 

Now, let’s explore biometric authentication in Android using an API (application programming interface). 

AndroidX Biometric API is a comprehensive solution for handling biometric authentication in Android applications. This API authenticates users with the help of biometrics and device credentials, while performing cryptographic operations. This API can be integrated easily into any Android project by adding it as a dependency. 

Here’s how it can be done in the build.gradle file of your app module:


dependencies {
…
    implementation "androidx.biometric:biometric-ktx:1.2.0-alpha04"
…
}

Features of AndroidX Biometric API

  • Analyses if a device possesses biometric authentication capabilities.
  • Provides a standard biometric prompt for facial or fingerprint recognition.
  • Provides callbacks for failed or successful authentication attempts.
  • Provides choices for pins, passwords, or patterns, in case you do not want to opt for biometric credentials.

AndroidX Biometric API and device capability

Since the AndroidX Biometric API is relatively new and not all devices possess biometric capabilities, it becomes necessary to check if a particular device is capable. The following extension function can be used to check biometric authentication capabilities:


fun Context.isBiometricCapable() : Int {
   val biometricManager = BiometricManager.from(this)
   biometricManager.canAuthenticate()
}

In this above scenario, we created a BiometricManager using the provided context that would assist canAuthenticate() in determining whether the hardware has biometric authentication capabilities. 

In some cases, devices may possess the requisite hardware for biometric authentication, but this BiometricPrompt can only be employed if users have registered their biometric information in their devices’ security settings. 

Moving on, if the canAuthenticate() is implemented, it will return the following results:

  • BIOMETRIC_SUCCESS: The device is ready to use a biometric prompt, implying the device is compatible with biometric software, and the user has added their biometric data to the device’s settings.
  • BIOMETRIC_ERROR_NONE_ENROLLED: The device supports biometrics, but the user has not added their facial or fingerprint data.
  • BIOMETRIC_ERROR_NO_HARDWARE: The device hardware is not capable of biometric authentication.
  • BIOMETRIC_ERROR_HW_UNAVAILABLE: Biometric features are currently unavailable.

Types of authentication in AndroidX Biometric API

Once you have completed the authentication process, you can check the authentication type by calling getAuthenticationType() to see if the user has authenticated using a device or biometric credential.

In this case, the getAuthenticationType() will provide the following results:

  • AUTHENTICATION_RESULT_TYPE_UNKNOWN: The authentication type is unknown.
  • AUTHENTICATION_RESULT_TYPE_DEVICE_CREDENTIAL: The user has authenticated using device credentials.
  • AUTHENTICATION_RESULT_TYPE_BIOMETRIC: The user has authenticated using device biometric authentication.

Building the biometric login prompt

Once we have determined that the user’s device has been authenticated, we can display a default system prompt requesting the user to authenticate using biometric credentials. This system-generated prompt is consistent across the apps that use it, thus creating a seamless user experience

Here’s how you can show the login prompt:

  • First, use PromptInfo to configure the desired messages and actions.
  • Then, Activity and Callback Handlers are used to initialize the BiometricPrompt

Step 1

The PromptInfo is developed using a builder class, BiometricPrompt.PromptInfo.Builder, which also populates it with the title, subtitle, and description.

fun getBiometricPromptInfo(
    title: String,
    subtitle: String,
    description: String
): BiometricPrompt.PromptInfo {

  val builder = BiometricPrompt.PromptInfo.Builder()
      .setTitle(title)
      .setSubtitle(subtitle)
      .setDescription(description)

  return builder.build()
}

Step 2

Now, you can initialize the BiometricPrompt and handle the callbacks with a custom listener from the calling activity.


fun initBiometricPrompt(
    activity: AppCompatActivity,
    listener: BiometricAuthListener
): BiometricPrompt {
  val executor = ContextCompat.getMainExecutor(activity)

  val callback = object : BiometricPrompt.AuthenticationCallback() {
    
      override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
         super.onAuthenticationError(errorCode, errString)
         listener.onBiometricAuthenticationError(errorCode, errString.toString())
     }

    override fun onAuthenticationFailed() {
      super.onAuthenticationFailed()
      Log.w(this.javaClass.simpleName, "Authentication failed for an unknown reason")
    }

    override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
      super.onAuthenticationSucceeded(result)
      listener.onBiometricAuthenticationSuccess(result)
    }
  }

  return BiometricPrompt(activity, executor, callback)
}

What does the above code snippet in Android achieve? It creates an executor to handle callback events and the callback object to obtain authentication events on Error, Failed, or Success. Then it updates custom listener methods with results and error messages. Finally, it returns a biometric prompt using the activity instance, executor, and callback reference.

You might be now wondering how to display the biometric prompt. Here’s how it’s done:

  • First, we need to setBiometricPromptInfo() by passing the title, subtitle, and description.
  • Then we need to initialize the BiometricPrompt using initBiometricPrompt() by passing calling Activity Instance and custom callback listener instance.
  • And finally, we show the prompt using the authenticate method by passing promptInfo biometricPrompt.authenticate(promptInfo).
fun initBiometricPrompt() {

val promptInfo = getBiometricPromptInfo(title, subtitle, description) 
val biometricPrompt = initBiometricPrompt(this, biometricAuthListener) 

biometricPrompt.authenticate(promptInfo)

}

And that is how you can build a biometric passwordless solution using BiometricPrompt. Now, isn't that awesome?

You also can further boost app security and sensitive data (and yes, we thought it best to surprise you with this 😆). So, now, coming to the question on your mind, how to boost app security even after biometric authentication? Well, the answer is adding cryptography to the biometric authentication workflow. But, good things take time, so keep a lookout for the sequel to biometric authentication in Android!

Make app security a priority

Start Building

Subir Chakraborty

Subir Chakraborty works at Mutual Mobile as a Senior Engineer I.

More by this author