Biometric enrollment and login (Android SDK)
This page covers the two ongoing operations a user performs on their device: a one-time enrollment, then biometric login on each return visit. Complete the Concepts and setup steps first - your program must be configured and the SDK initialized.
Enroll a device
Enrollment is a one-time flow that registers the user's device as an authentication factor. It runs once per user, per device.
Overview
The following sequence diagram shows the high-level flow of the biometric enrollment process:
Start enrollment
With the SDK and PSAPSA Push Step-up Authentication - the mechanism in our mobile SDKs that delivers a step-up challenge to an enrolled device as a push notification and verifies it with the user's device biometrics. PSA covers device enrollment, biometric login, and biometric verification of SCA challenges for sensitive operations such as outgoing wire transfers or accessing card details. Exposed as `UXComponents.psa` on iOS and Android and via `initializePSA` on React Native. component initialized, start enrollment with startEnrollment:
UXComponents.psa.startEnrollment(
activity = this,
certificates = R.array.com_google_android_gms_fonts_certs,
completion = { result ->
when (result) {
is WeavrEnrollmentResult.Completed ->
// Enrollment finished successfully
is WeavrEnrollmentResult.InitialisationError ->
// Flow could not be initialised: result.error
is WeavrEnrollmentResult.CryptographyError ->
// Cryptography operation failed: result.error
is WeavrEnrollmentResult.FailedBiometricsChallenge ->
// User failed the biometric prompt
is WeavrEnrollmentResult.Unauthorized ->
// User token is invalid or expired
is WeavrEnrollmentResult.UserDoesNotConsent ->
// User cancelled or dismissed the flow
is WeavrEnrollmentResult.FailedToLoadBrand ->
// Brand configuration could not be loaded, or biometrics is disabled for this project
is WeavrEnrollmentResult.NoPhoneNumberAvailable ->
// No phone number available for SMS OTP
is WeavrEnrollmentResult.NoBiometricsAvailable ->
// No usable biometrics enrolled: result.availability
is WeavrEnrollmentResult.ChallengeFailed ->
// Challenge failed: result.cause
}
}
)
Result reference
| Result | Description |
|---|---|
Completed | Enrollment finished successfully. |
InitialisationError | The enrollment flow could not be initialised. |
CryptographyError | A cryptography operation failed. |
FailedBiometricsChallenge | The user failed the biometric prompt. |
Unauthorized | The user token stored in the SDK is invalid or expired. |
UserDoesNotConsent | The user cancelled or dismissed the flow. |
FailedToLoadBrand | Brand configuration could not be loaded, or biometrics is disabled for the project. When biometrics is disabled, the enrollment UI is not shown and this result is returned immediately. |
NoPhoneNumberAvailable | No phone number is available for the SMS OTP step. |
NoBiometricsAvailable | The device has no usable biometrics enrolled. |
ChallengeFailed | The challenge failed; inspect result.cause for details. |
You can brand the enrollment screens by adjusting colors, font, and text size in the Embedder PortalEmbedder Portal A web-based portal where embedders can access their Weavr account, manage API credentials, configure settings, view dashboards, and access documentation. The portal provides access to both sandbox and production environments, with separate credentials for each. under Settings > Authentication Config > Biometric.
Using startPSAEnrollment (deprecated)
startPSAEnrollment is deprecated as of v3.9.0 and will be removed in a future release. Use startEnrollment instead. See the v3.9.0 migration guide for step-by-step instructions.
// Check all permissions needed for biometric authentication
UXComponents.psa.checkAllPermissionsRequiredByPSA(this)
// Start enrolment 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
"Enrolment Error"
-> // Handle enrolment failure
"Internal Server Error"
-> // Handle server error
"Pin Error"
-> // Handle PIN verification failure
else -> // Handle other errors
}
}
override fun onSuccess(message: String) {
// Handle successful enrolment
}
}
)
Troubleshooting enrollment
"Internal configuration error" snackbar is shown when the Android SDK starts device authorization but a required local value is missing. Specifically, the consent screen verifies both the UI keyUI key A public key that authorizes Weavr's Secure UI components - the inputs and displays in our Web, Android, iOS, and React Native SDKs that handle passwords, PINs, card details, and KYC/KYB flows. Unlike the API key, the UI key isn't an API credential; you don't call REST endpoints with it. It's safe to embed in client-side code, and Sandbox and Live each have their own UI key. and a Play Integrity token are present before proceeding. The Integrity token is fetched right after PSAPSA Push Step-up Authentication - the mechanism in our mobile SDKs that delivers a step-up challenge to an enrolled device as a push notification and verifies it with the user's device biometrics. PSA covers device enrollment, biometric login, and biometric verification of SCA challenges for sensitive operations such as outgoing wire transfers or accessing card details. Exposed as `UXComponents.psa` on iOS and Android and via `initializePSA` on React Native. initialization via a config call that returns a cloud project number, then the Play Integrity API is called.
This usually fails if:
- The SDK isn't fully initialized before starting enrollment (missing UI keyUI key A public key that authorizes Weavr's Secure UI components - the inputs and displays in our Web, Android, iOS, and React Native SDKs that handle passwords, PINs, card details, and KYC/KYB flows. Unlike the API key, the UI key isn't an API credential; you don't call REST endpoints with it. It's safe to embed in client-side code, and Sandbox and Live each have their own UI key. or Integrity token).
- The Integrity token hasn't been fetched yet (timing).
- The device/Google Play Services/Integrity setup can't issue a token for the project number.
Ensure that:
- You call both SDK init and PSAPSA Push Step-up Authentication - the mechanism in our mobile SDKs that delivers a step-up challenge to an enrolled device as a push notification and verifies it with the user's device biometrics. PSA covers device enrollment, biometric login, and biometric verification of SCA challenges for sensitive operations such as outgoing wire transfers or accessing card details. Exposed as `UXComponents.psa` on iOS and Android and via `initializePSA` on React Native. init on app startup (before showing the consent screen) and with the same environment as your backend:
- You initialize the SDK with your UI keyUI key A public key that authorizes Weavr's Secure UI components - the inputs and displays in our Web, Android, iOS, and React Native SDKs that handle passwords, PINs, card details, and KYC/KYB flows. Unlike the API key, the UI key isn't an API credential; you don't call REST endpoints with it. It's safe to embed in client-side code, and Sandbox and Live each have their own UI key..
- You initialize PSAPSA Push Step-up Authentication - the mechanism in our mobile SDKs that delivers a step-up challenge to an enrolled device as a push notification and verifies it with the user's device biometrics. PSA covers device enrollment, biometric login, and biometric verification of SCA challenges for sensitive operations such as outgoing wire transfers or accessing card details. Exposed as `UXComponents.psa` on iOS and Android and via `initializePSA` on React Native..
- Google Play services is present (not a non‑GMS emulator)
- Google-services.json is present in the Android app and matches the same Firebase/Cloud project you use for Play Integrity.
- If you are using any proxy tool, disable it and check again.
ENROLLMENT_FAILED: Invalid Origin on Android productionThis error means the enrollment request returned HTTP 403 from the backend. It is distinct from the "Internal configuration error" preceding it - that error is a local missing-token issue; this one is a server rejection.
The most common cause when Sandbox works but production fails is that Play Integrity is not fully configured for your production app. Complete both setup steps:
- Enable the Play Integrity API in GCP Console → APIs & Services.
- Link your app in Google Play Console → Release → App integrity.
Also confirm:
- The
uiKeypassed toUXComponents.initialize()belongs to the Production programmeProgramme A programme represents your application within Weavr. Everything you create - Identities, Instruments, Transactions - sits beneath a Programme. When you register as an Embedder, you receive a Programme in the Sandbox and, once approved, one in Production. (not Sandbox). - You are testing via Google Play Internal Testing, not a sideloaded APK. Production Play Integrity checks require a Play Store-distributed build.
- Even when installed via the Play Store, a debug-signed APK may not pass Play Integrity on production. Use a release-signed build for production testing.
Check enrollment status
Verify device enrollment 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
}
}
}
)
Biometric login
Biometric login overview
For first-time user-access, for a user to be fully logged in, a biometric login is required following the enrollment. Returning users should only complete a biometric login, not an enrollment every time.
The Biometrics Authentication component is designed for a single user on one device. If a different user tries to enroll, it shows as the device is already enrolled. See un-enrollment section for more details.
The following sequence diagram shows the high-level flow of a 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
}
)
Automatic fallback to password or passcode
The SDK automatically handles fallback to password or passcode authentication when biometric authentication fails:
-
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 or passcode entry screen
- Users can choose between password or passcode authentication
- Handles verification for both authentication methods
- Manages retry attempts for both options
- Provides appropriate error messages
-
Error handling
- Handles invalid password or passcode attempts
- Manages verification failures for both methods
- Provides clear user feedback
Un-enrollment
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 Weavr API Unlink endpoint.