Biometrics - Android
Prerequisites
Before implementing authentication via biometrics, you must first integrate the Password Component into your app. This is required because:
- Users must authenticate with their password before enrolling for biometrics. The password must be tokenised for secure communication.
- The user must have a password set, because if biometric authentication fails (e.g. fingerprint not recognised), the password is required as a fallback identification method.
Required components
Password component
- Required for initial authentication
- Used as the fallback authentication method
- Must be tokenised for security
Follow the Password Component guide to implement this in your app.
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
-
Weavr SDK classes: The rules prevent ProGuard from obfuscating or removing essential SDK classes and their members.
-
Gson support: The SDK uses Gson for JSON serialization/deserialization. These rules ensure proper handling of annotated fields and type adapters.
-
Play Integrity: Required for device integrity checks and security features.
-
Crash reporting: Maintains readable stack traces for debugging.
Failure to include these ProGuard rules may result in runtime crashes or unexpected behaviour in the SDK's functionality.
Implementation flows
First time only: Enrol 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 manager with error handling
try {
UXComponents.psa.initialise(
this,
PsaENV.SANDBOX,
)
} 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 FCM token in the SDK
UXComponents.psa.updateDeviceToken(
token,
object : WeavrResult<UpdateDeviceTokenResponse, ErrorResponse> {
override fun onSuccess(result: UpdateDeviceTokenResponse?) {
// Handle successful FCM token update
}
override fun onFailure(error: ErrorResponse) {
// Handle FCM 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 FCM 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 FCM 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
}
}
)
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 operations
Biometric login overview
For first-time user-access, for a user to be fully logged in, a biometric login is required following the enrolment. Returning users should only complete a biometric login, not an enrolment every time.
The Biometrics Authentication component is designed for a single user on one device. If a different user tries to enrol, it will show as the device is already enrolled. See un-enrolment section for more details.
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
}
}
override fun onSuccess(loginResponse: WeavrSecureLoginData?) {
// Handle successful login
// Store the token for future use
val token = loginResponse?.token
}
},
onForgotPassword = {
// Handle forgot password scenario
}
)
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:
-
Challenge reception
- Challenges are received through push notifications
- The SDK automatically processes incoming challenges
-
Challenge verification
- The SDK verifies challenges using biometric authentication
- Passcode fallback is automatically triggered after 3 failed attempts
-
Challenge UI
- The SDK provides built-in UI for challenge handling
- UI follows the branding guidelines
-
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 password
The SDK automatically handles all aspects of the fallback to password process:
-
After failed biometric attempts
- Automatically triggered after 3 failed biometric attempts
- No manual intervention required
- SDK handles the entire fallback flow
-
Fallback flow
- SDK automatically shows password entry screen
- Handles password verification
- Manages retry attempts
- Provides appropriate error messages
-
Error handling
- Handles invalid password attempts
- Manages password 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:
-
Uninstalling (and re-installing) the app.
-
By triggering a call from your backend to the multi API Unlink endpoint.