Skip to main content

Biometrics - Android

Prerequisites

Before implementing authentication via biometrics, you must first integrate the Passcode Component into your app. This is required because:

  1. Users must authenticate with their passcode before enrolling for biometrics. The passcode must be tokenised for secure communication.
  2. The user must have a passcode set, because if biometric authentication fails (e.g. fingerprint not recognised), the passcode is required as a fallback identification method.

Required components

Passcode component

  • Required for initial authentication
  • Used as the fallback authentication method
  • Must be tokenised for security

Follow the Passcode Component guide to implement this in your app.

Tokenisation

  • Required for secure passcode handling
  • Enables secure communication with backend
  • Supports data matching and grouping

Learn more about Weavr Tokenisation in the Product documentation.

Get started

Make sure you have read the overall Android Get Started section for guidance on setting up, installing, and initialising the SDK.

The Weavr Android SDK enables you to integrate the Biometric Authentication component into your Android app. To use the Weavr Android SDK, ensure you have obtained the necessary credentials from the Embedder Portal. Please add the values in a configuration file or wherever is convenient to store securely in your app.

UI_KEY = "Your UI key goes here"
API_KEY = "Your API key goes here"
OWT_PROFILE_ID = "Your profile id goes here"
SEND_PROFILE_ID = "Your send profile "

Required permissions

Add these permissions to your AndroidManifest.xml:

<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

ProGuard configuration

When integrating the Weavr SDK into your Android app, you need to add specific ProGuard rules to ensure proper functionality. Add the following rules to your app's proguard-rules.pro file:

# Keep Weavr SDK classes and their members
-keep class io.weavr.** { *; }
-keep class io.weavr.components.data.dto** { *; }
-keep class io.weavr.components.sumsub.data** { *; }
-keep class io.weavr.components.SecureEditText { *; }
-keep class io.weavr.components.weavrbiometric.WeavrPsaManager { *; }

# Keep required interfaces and resources
-keep class * implements android.graphics.drawable.Drawable { *; }
-keep class * implements android.content.res.Resources { *; }

# Keep Gson related classes and annotations
-keepattributes Signature
-keepattributes *Annotation*
-keep class * extends com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer

# Keep serialized fields
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}

# Keep Play Integrity related classes
-keep class com.google.android.play.core.integrity.** { *; }
-keep interface com.google.android.play.core.integrity.** { *; }
-keep class com.google.android.gms.tasks.** { *; }

# Keep Approov related classes
-keep class io.approov.** { *; }
-keep class com.criticalblue.** { *; }
-keep class com.criticalblue.approovsdk.** {
<init>(...);
*;
}

# Keep crash reporting information
-keepattributes SourceFile,LineNumberTable
-keep public class * extends java.lang.Exception

Why these rules are needed

  1. Weavr SDK classes: The rules prevent ProGuard from obfuscating or removing essential SDK classes and their members.

  2. Gson support: The SDK uses Gson for JSON serialization/deserialization. These rules ensure proper handling of annotated fields and type adapters.

  3. Play Integrity: Required for device integrity checks and security features.

  4. Crash reporting: Maintains readable stack traces for debugging.

warning

Failure to include these ProGuard rules may result in runtime crashes or unexpected behaviour in the SDK's functionality.

Implementation flow

Enrolling a device overview

The following sequence diagram shows the high-level flow of the biometric enrolment process:

Initialise the SDK

To initialise both the main SDK and the Biometric Authentication component:

// Initialize the main SDK
UXComponents.initialise(this, ENV.SANDBOX, UI_KEY)

// Initialize the biometric component with a custom logger
class CustomLogger : ExceptionLogger {
override fun exception(message: String?, exception: Exception?) {
// Implement your logging logic here
Log.e("WeavrSDK", message ?: "", exception)
}

override fun setUserIdentificator(identifier: String?) {
// Implement user identification logic if needed
}
}

// Initialize the biometric manager with error handling
try {
UXComponents.psa.initialise(
this,
PsaENV.SANDBOX,
logger = CustomLogger()
)
} catch (e: Exception) {
// Handle initialization error
Log.e("WeavrSDK", "Failed to initialize biometric component", e)
}

Push notification setup

Before checking biometric availability, you must set up Firebase Cloud Messaging (FCM) for push notifications:

Configure Firebase Cloud Messaging

Add the following to your AndroidManifest.xml:


<service android:name=".YourFirebaseMessagingService" android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>

Create Firebase messaging service

Create a service that extends WeavrFCMService:

class YourFirebaseMessagingService : WeavrFCMService() {
override fun onMessageReceived(remoteMessage: RemoteMessage) {
super.onMessageReceived(remoteMessage)
// Handle any additional notification logic here
}

override fun onNewToken(token: String) {
super.onNewToken(token)
// Update the token in the SDK
UXComponents.psa.updateDeviceToken(
token,
object : WeavrResult<UpdateDeviceTokenResponse, ErrorResponse> {
override fun onSuccess(result: UpdateDeviceTokenResponse?) {
// Handle successful token update
}
override fun onFailure(error: ErrorResponse) {
// Handle token update failure
}
}
)
}
}

Register broadcast receiver

Register a broadcast receiver to handle challenges:

private val foregroundMsgReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent != null) {
UXComponents.psa.handleIntent(
intent,
activity = context as Activity,
PreferenceRepo(context).getAppPNS().toString(),
weavrPsaSessionListener = object : WeavrPsaSessionListener {
override fun onFailed(error: ErrorResponse) {
// Handle challenge failure
}

override fun onSuccess(message: String, challengeType: PSAChallengeType, challengeId: String) {
// Handle successful challenge
}
}
)
}
}
}

// Register the receiver
val filter = IntentFilter()
filter.addAction(WeavrFCMService.WEAVR_INTENT_ACTION)
registerReceiver(foregroundMsgReceiver, filter)

Update device token

When you receive a new FCM token, to update it in the SDK:

UXComponents.psa.updateDeviceToken(
fcmToken,
object : WeavrResult<UpdateDeviceTokenResponse, ErrorResponse> {
override fun onSuccess(result: UpdateDeviceTokenResponse?) {
// Handle successful token update
}
override fun onFailure(error: ErrorResponse) {
when (error.message) {
"Push Notification Error" -> // Handle push notification error
"Service Unavailable"
-> // Handle service unavailability
else -> // Handle other errors
}
}
}
)

Device enrolment

To start enrolment:

// Check all permissions needed for biometric authentication
UXComponents.psa.checkAllPermissionsRequiredByPSA(this)

// Start enrollment with error handling
UXComponents.psa.startPSAEnrollment(
activity = this,
firebaseToken = firebaseToken,
authToken = authToken,
certificates = R.array.certificates,
enrollmentListener = object : WeavrPSAListener {
override fun onFailed(error: ErrorResponse) {
when (error.message) {
"Push Notification Error" -> // Handle push notification setup failure
"Enrollment Error"
-> // Handle enrollment failure
"Internal Server Error"
-> // Handle server error
"Pin Error"
-> // Handle PIN verification failure
else -> // Handle other errors
}
}
override fun onSuccess(message: String) {
// Handle successful enrollment
}
}
)
tip

You have the ability to brand this page by adjusting colours, font, and text size. You can this in the embedder portal under Settings > Authentication Config > Biometric

Biometric login overview

The following sequence diagram shows the high-level flow of a biometric login:

Biometric login

To implement biometric login:

UXComponents.psa.startBiometricPsaLogin(
activity = activity,
biometricLoginListener = object : WeavrLoginListener {
override fun onFailed(error: ErrorResponse) {
when (error.message) {
"Authorization Error" -> {
// Handle biometric authorization failure
}
"Transaction Failed" -> {
// Handle transaction failure (e.g., backend rejected transaction)
}
"Pin Error" -> {
// Handle PIN verification failure
}
else -> {
// Handle other or unknown errors
}
}
}
override fun onSuccess(loginResponse: String?) {
// Handle successful login
// loginResponse may contain a token or status string
}
},
onForgotPasscode = {
// Handle forgot passcode scenario (e.g., show reset UI)
}
)

Check enrolment status

Verify device enrolment status:

UXComponents.psa.isPSAEnrolled(
context,
object : WeavrPSAStatusListener {
override fun onFailed(error: ErrorResponse) {
when (error.message) {
"Initialization Error" -> // Handle initialization error
"Server Error"
-> // Handle server error
else -> // Handle other errors
}
}
override fun onSuccess(isEnrolled: Boolean) {
if (isEnrolled) {
// Device is enrolled
} else {
// Device is not enrolled
}
}
}
)

Challenge handling

For general context about challenges, see the Step-Up Authentication and Transaction Confirmation sections of the product documentation.

The SDK automatically handles all challenge-related operations:

  1. Challenge reception

    • Challenges are received through push notifications
    • The SDK automatically processes incoming challenges
  2. Challenge verification

    • The SDK verifies challenges using biometric authentication
    • Passcode fallback is automatically triggered after 3 failed attempts
  3. Challenge UI

    • The SDK provides built-in UI for challenge handling
    • UI follows the branding guidelines
  4. Triggering a Challenge

Challenges can be triggered by user actions from within your app, namely transaction confirmation for OWTs, Sends, or adding a payment beneficiary; or they can be triggered by a user action outside your app, specifically using a card for an e-commerce transaction that requires 3DS approval.

Example: Embedder triggered challenge

Transaction Confirmation challenges for OWTs and Sends are triggered via the Confirmation Challenges endpoint. A challenge to verify a batch of beneficiaries can be triggered via the Beneficiaries endpoint.

Example: 3DS challenge

For the approval of an e-commerce transactions via 3DS, the challenge is triggered by an action outside of your app: a purchase by the user at an online checkout, and follows the sequence below:

Automatic fallback to passcode

The SDK automatically handles all aspects of the fallback to passcode process:

  1. After failed biometric attempts

    • Automatically triggered after 3 failed biometric attempts
    • No manual intervention required
    • SDK handles the entire fallback flow
  2. Fallback flow

    • SDK automatically shows passcode entry screen
    • Handles passcode verification
    • Manages retry attempts
    • Provides appropriate error messages
  3. Error handling

    • Handles invalid passcode attempts
    • Manages passcode verification failures
    • Provides user feedback

Un-enrolment

A device can only be enrolled to one user for Biometrics Authentication at any one time. Therefore another user cannot use the same device for Biometric Authentication in your app unless the previous user has been unenrolled. This is of particular note when testing your app with the Biometrics Authentication component, where testers may share devices.

The current user can be unenrolled by either:

  1. Uninstalling (and re-installing) the app.

  2. By triggering a call from your backend to the multi API Unlink endpoint.