Show a biometric authentication dialog

One method of protecting sensitive information or premium content within your app is to request biometric authentication, such as using face recognition or fingerprint recognition. This guide explains how to support biometric login flows in your app.

Check that biometric authentication is available

You can check if a device supports biometric authentication prior to invoking BiometricPrompt by using the canAuthenticate() method in the BiometricManager class.

The following code snippet shows how to invoke this method:

Kotlin

val biometricManager = BiometricManager.from(this)
when (biometricManager.canAuthenticate()) {
    BiometricManager.BIOMETRIC_SUCCESS ->
        Log.d("App can authenticate using biometrics.")
    BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE ->
        Log.e("No biometric features available on this device.")
    BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE ->
        Log.e("Biometric features are currently unavailable.")
    BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED ->
        Log.e("The user hasn't associated any biometric credentials " +
        "with their account.")
}

Java

BiometricManager biometricManager = BiometricManager.from(this);
switch (biometricManager.canAuthenticate()) {
    case BiometricManager.BIOMETRIC_SUCCESS:
        Log.d("App can authenticate using biometrics.");
        break;
    case BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE:
        Log.e("No biometric features available on this device.");
        break;
    case BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE:
        Log.e("Biometric features are currently unavailable.");
        break;
    case BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED:
        Log.e("The user hasn't associated any biometric credentials " +
            "with their account.");
        break;
}

Display the login prompt

To display a system prompt that requests the user to provide biometric credentials, use the Biometric library. This system-provided dialog is consistent across the apps that use it, creating a more trustworthy user experience. An example dialog appears in Figure 1.

Screenshot showing dialog
Figure 1. System dialog requesting biometric authentication

To add biometric authentication to your app using the Biometric library, complete the following steps:

  1. In your app's app/build.gradle file, add a dependency for the Biometric library:

    dependencies {
        implementation 'androidx.biometric:biometric:1.0.0-beta01'
    }
    
  2. In the activity or fragment that hosts the biometric login dialog, display the dialog using the logic shown in the following code snippet:

    Kotlin

    private val executor = Executor { }
    
    override fun onCreate(savedInstanceState: Bundle?) {
        // ...
        // Prompt appears when user clicks "Log in"
        val biometricLoginButton: Button = findViewById(R.id.biometric_login)
        biometricLoginButton.setOnClickListener { showBiometricPrompt() }
    }
    
    private fun showBiometricPrompt() {
        val promptInfo = BiometricPrompt.PromptInfo.Builder()
                .setTitle("Biometric login for my app")
                .setSubtitle("Log in using your biometric credential")
                .setNegativeButtonText("Cancel")
                .build()
    
        val 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)
                val authenticatedCryptoObject: BiometricPrompt.CryptoObject =
                        result.getCryptoObject()
                // User has verified the signature, cipher, or message
                // authentication code (MAC) associated with the crypto object,
                // so you can use it in your app's crypto-driven workflows.
            }
    
            override fun onAuthenticationFailed() {
                super.onAuthenticationFailed()
                Toast.makeText(applicationContext, "Authentication failed",
                    Toast.LENGTH_SHORT)
                    .show()
            }
        })
    
        // Displays the "log in" prompt.
        biometricPrompt.authenticate(promptInfo)
    }
    

    Java

    private Handler handler = new Handler();
    
    private Executor executor = new Executor() {
        @Override
        public void execute(Runnable command) {
            handler.post(command);
        }
    };
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // ...
        // Prompt appears when user clicks "Log in"
        Button biometricLoginButton = findViewById(R.id.biometric_login);
        biometricLoginButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                showBiometricPrompt();
            }
        });
    }
    
    private void showBiometricPrompt() {
        BiometricPrompt.PromptInfo promptInfo =
                new BiometricPrompt.PromptInfo.Builder()
                .setTitle("Biometric login for my app")
                .setSubtitle("Log in using your biometric credential")
                .setNegativeButtonText("Cancel")
                .build();
    
        BiometricPrompt biometricPrompt = new BiometricPrompt(MainActivity.this,
                executor, new BiometricPrompt.AuthenticationCallback() {
            @Override
            public void onAuthenticationError(int errorCode,
                    @NonNull CharSequence errString) {
                super.onAuthenticationError(errorCode, errString);
                Toast.makeText(getApplicationContext(),
                    "Authentication error: " + errString, Toast.LENGTH_SHORT)
                    .show();
            }
    
            @Override
            public void onAuthenticationSucceeded(
                    @NonNull BiometricPrompt.AuthenticationResult result) {
                super.onAuthenticationSucceeded(result);
                BiometricPrompt.CryptoObject authenticatedCryptoObject =
                        result.getCryptoObject();
                // User has verified the signature, cipher, or message
                // authentication code (MAC) associated with the crypto object,
                // so you can use it in your app's crypto-driven workflows.
            }
    
            @Override
            public void onAuthenticationFailed() {
                super.onAuthenticationFailed();
                Toast.makeText(getApplicationContext(), "Authentication failed",
                    Toast.LENGTH_SHORT)
                    .show();
            }
        });
    
        // Displays the "log in" prompt.
        biometricPrompt.authenticate(promptInfo);
    }
    

Authenticate without explicit user action

By default, the system requires users to perform a specific action, such as pressing a button, after their biometric credentials are accepted. This configuration is preferable if your app is showing the dialog to confirm a sensitive or high-risk action, such as making a purchase.

If your app shows a biometric authentication dialog for a lower-risk action, however, you can provide a hint to the system that the user doesn't need to perform the action to authenticate. This hint can allow the user to view content in your app more quickly after re-authenticating using a passive modality, such as face- or iris-based recognition. To provide this hint, pass false into the setConfirmationRequired() method.

Figure 2 shows two versions of the same dialog. One version requires an explicit user action, and the other version doesn't.

Screen capture of dialog Screen capture of dialog
Figure 2. Face authentication without user confirmation (top) and with user confirmation (bottom)

The following code snippet shows how to present a dialog that doesn't require an explicit user action to complete the authentication process:

Kotlin

// Allows user to authenticate without performing an action, such as pressing a
// button, after their biometric credential is accepted.
val promptInfo = BiometricPrompt.PromptInfo.Builder()
        .setTitle("Biometric login for my app")
        .setSubtitle("Log in using your biometric credential")
        .setNegativeButtonText("Cancel")
        .setConfirmationRequired(false)
        .build()

Java

// Allows user to authenticate without performing an action, such as pressing a
// button, after their biometric credential is accepted.
BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
        .setTitle("Biometric login for my app")
        .setSubtitle("Log in using your biometric credential")
        .setNegativeButtonText("Cancel")
        .setConfirmationRequired(false)
        .build();

Allow for fallback to non-biometric credentials

If the user cannot authenticate using their biometric credentials, you can allow them to authenticate using their device PIN, pattern, or password by passing true into the setDeviceCredentialAllowed() method. The following code snippet shows how to provide this fallback support:

Kotlin

// Allows user to authenticate using a PIN, pattern, or password.
val promptInfo = BiometricPrompt.PromptInfo.Builder()
        .setTitle("Biometric login for my app")
        .setSubtitle("Log in using your biometric credential")
        .setNegativeButtonText("Cancel")
        .setDeviceCredentialAllowed(true)
        .build()

Java

// Allows user to authenticate using a PIN, pattern, or password.
BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
        .setTitle("Biometric login for my app")
        .setSubtitle("Log in using your biometric credential")
        .setNegativeButtonText("Cancel")
        .setDeviceCredentialAllowed(true)
        .build();