March 29, 2021

Fingerprint Authentication using Android Biometric API

By Lalit Vasan


Generally, to authenticate into any android application you have to manually enter the username and password. Also, if you forgot the password or username then you have to recover it by going through a series of steps. Now, this authentication method is getting old and applications are switching to Fingerprint Authentication. By adding Fingerprint authentication to your application you do not need to remember the password. Also, no two persons can have the same Fingerprint, so, we need not worry about authenticity.

The Android Biometric Library makes adding these features easy and fun. This library is available back to API level 23 and includes a biometric prompt UI out of the box. It also lets you see if a device supports biometric hardware with a single method call.

Advantages of Using Biometric Authentication

  1. High security and assurance – Biometric identification provides the answers to “something a person has and is” and helps verify identity
  2. User Experience – Convenient and fast
  3. Non-transferrable – Everyone has access to a unique set of biometrics
  4. Spoof-proof – Biometrics is hard to fake or steal

Let’s Get it Working

In this tutorial, we are going to learn how to add fingerprint authentication using android biometric API to the android application. To really understand the process we will create an app. The App contains a simple view having buttons to authenticate the user with fingerprint and pin. I assume that you have already created a new android project. You can also download or explore code on GitHub.

DownloadCode
 
github

Step 1) Add androidx.biometric dependency.

Open build.gradle (Module:app) and add the following library dependency within dependencies:

implementation 'androidx.biometric:biometric:1.1.0'

Click Sync now to sync the project so you can use the Biometric API.

Step 2) Update activity_main.xml.

Update the layout file for the MainActivity.kt i.e activity_man.xml and add the below code in the layout file. This code will create two buttons with the label “Biometric Authentication” and “Biometric Authentication + Pin Password”.

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/buttonBiometricAuth"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:backgroundTint="@color/colorAccent"
        android:text="Biometric Authentication"
        android:textAllCaps="false"
        android:textColor="@android:color/white"
        android:textSize="18sp" />

    <Button
        android:id="@+id/buttonBiometricAuthWithPin"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="60dp"
        android:backgroundTint="@color/colorAccent"
        android:text="Biometric Authentication + Pin Password"
        android:textAllCaps="false"
        android:textColor="@android:color/white"
        android:textSize="18sp" />

</androidx.appcompat.widget.LinearLayoutCompat>
Main Screen

Main Screen





Step 3) Update MainActivity.kt class.

Open class named MainActivity and add below code. Here I have written the code to registered the button’s onClick listeners and functions to add logic for biometric authentication.
initBiometricPrompt() :- function initializes the object for biometric prompt configuration.
Executor that performs tasks on the main thread
BiometricPrompt manages a system-provided biometric prompt
BiometricPrompt.PromptInfo have set of configurable options for how the BiometricPrompt should appear and behave. Here create two object for BiometricPrompt.PromptInfo, one is for only fingerprint authentication and other one is for fingerprint + pin authentication.

isBioMetricSupported() :- function initalizes the object of BiometricManager that provides system information related to biometrics (e.g. fingerprint, face, etc.). This function also checks that if app can authenticate via biometric and print the Biometric Status in Logs.

All the function and objects are created now call BiometricPrompt’s authenticate(BiometricPrompt.PromptInfo info) method and pass prompt info respective object to show the prompt for biometric. Refer to the below images to check how the biometric pop-up will look.

package com.androidtutorialshub.biometric_authentication

import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.biometric.BiometricManager
import androidx.biometric.BiometricPrompt
import androidx.core.content.ContextCompat
import java.util.concurrent.Executor

class MainActivity : AppCompatActivity() {

    private lateinit var executor: Executor
    private lateinit var biometricPrompt: BiometricPrompt
    private lateinit var promptInfo: BiometricPrompt.PromptInfo
    private lateinit var promptInfoWithPin: BiometricPrompt.PromptInfo

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // initialize the biometric prompt
        initBiometricPrompt()

        // login button on click listener
        findViewById<Button>(R.id.buttonBiometricAuth).setOnClickListener {
            // check if biometric supported
            if (isBioMetricSupported()) {
                // call authenticate method to show prompt for biometric
                biometricPrompt.authenticate(promptInfo)
            } else {
                // call toast if biometric not supported
                Toast.makeText(this, "Biometric not supported", Toast.LENGTH_LONG).show()
            }
        }

        // login button on click listener
        findViewById<Button>(R.id.buttonBiometricAuthWithPin).setOnClickListener {
            // check if biometric supported
            if (isBioMetricSupported()) {
                // call authenticate method to show prompt for biometric + pin
                biometricPrompt.authenticate(promptInfoWithPin)
            } else {
                // call toast if biometric not supported
                Toast.makeText(this, "Biometric not supported", Toast.LENGTH_LONG).show()
            }
        }
    }

    /**
     * method to initialize the biometric prompt configuration
     */
    private fun initBiometricPrompt() {
        // executor to enqueued tasks on the main thread
        executor = ContextCompat.getMainExecutor(this)

        // biometricPrompt to show biometric pop up for authentication
        biometricPrompt = BiometricPrompt(
            this,
            executor,
            object : BiometricPrompt.AuthenticationCallback() {
                // authentication error callback
                override fun onAuthenticationError(
                    errorCode: Int,
                    errString: CharSequence
                ) {
                    super.onAuthenticationError(errorCode, errString)
                    Toast.makeText(
                        applicationContext,
                        "Authentication error: $errString", Toast.LENGTH_SHORT
                    ).show()
                }

                // authentication success  callback
                override fun onAuthenticationSucceeded(
                    result: BiometricPrompt.AuthenticationResult
                ) {
                    super.onAuthenticationSucceeded(result)
                    Toast.makeText(
                        applicationContext,
                        "Authentication succeeded!", Toast.LENGTH_SHORT
                    ).show()
                }

                // authentication failure callback
                override fun onAuthenticationFailed() {
                    super.onAuthenticationFailed()
                    Toast.makeText(
                        applicationContext, "Authentication failed",
                        Toast.LENGTH_SHORT
                    ).show()
                }
            })

        // promptInfo to initialize the pop up title, subtitle and negative button text
        promptInfo = BiometricPrompt.PromptInfo.Builder()
            .setTitle("Login to Android Tutorials Hub")
            .setSubtitle("Biometric Authentication")
            .setDescription("Use your fingerprint to access the app")
            .setNegativeButtonText("Cancel")
            .build()

        // promptInfo to initialize the pop up title, subtitle and pin password option enabled
        promptInfoWithPin = BiometricPrompt.PromptInfo.Builder()
            .setTitle("Login to Android Tutorials Hub")
            .setSubtitle("Biometric Authentication + Pin Password")
            .setDescription("Use your fingerprint or pin to access the app")
            .setDeviceCredentialAllowed(true)
            .build()
    }

    /**
     * method to check biometric is supported
     *
     * return true/false
     */
    private fun isBioMetricSupported(): Boolean {

        // biometric manager
        val biometricManager = BiometricManager.from(this)

        // check if app can authenticate via biometric
        when (biometricManager.canAuthenticate()) {
            // success
            BiometricManager.BIOMETRIC_SUCCESS -> {
                Log.e("Biometric Status", "App can authenticate using biometrics.")
                return true
            }
            // error no hardware
            BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> {
                Log.e("Biometric Status", "No biometric features available on this device.")
                return false
            }
            // error feature unavailable
            BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> {
                Log.e("Biometric Status", "Biometric features are currently unavailable.")
                return false
            }
            // error no biometric enrolled
            BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> {
                Log.e(
                    "Biometric Status",
                    "The user hasn't associated any biometric credentials with their account."
                )
                return false
            }
        }
        return false
    }

}





Testing on a Physical Device

With the app is now complete, debug the app on a physical Android device. Click on any of the two buttons to perform biometric authentication. Once the biometric pop-up appears place your fingertip on the fingerprint scanner. If Fingerprint Authentication is successful, you will be shown the Authentication succeeded! message.

Fingerprint Authentication

Fingerprint Authentication



Fingerprint + PIN Authentication

Fingerprint + PIN Authentication



Biometric Authentication

DownloadCode
 
github

Please feel free to comment as well as ask questions. And, yeah! If this post helps you please do share!

Enjoy Coding and Share Knowledge