Authenticators
Currently the Android SDK offers three methods for user authentication:
-
PIN
is a default type of user authentication where user has to provide set of digits in order to authenticate. This method of authenticator has to be registered during user registration and can't be deregistered even when other authenticators are registered. When the user can't authenticate with another method (such as fingerprint), the Android SDK allows them to use their PIN instead. -
FINGERPRINT
is a native Android fingerprint authentication (using the Android API). In order to use it on a device, all requirements and availability have to be met. -
CUSTOM
is all third-party custom authenticators that are added to the app by the app developer. In order to use such authenticators, the app developer needs to enable the custom authenticator functionality in the IDAAS-core, provide proper scripts in the extension engine, and interface implementations in the Android SDK.
Authenticator interface
The OneginiAuthenticator
interface allows you to take a control over all authentication possibilities offered by the device. Currently the Android SDK supports three different types of user authentication: PIN (default), fingerprint, and custom authentication.
The OneginiAuthenticator
interface presents the following methods:
getType()
: This method should be used to distinguish all types of authentication. Currently all possible authentication types are: PIN,FINGERPRINT*
, CUSTOM.getId()
: This method should be used to distinguish different CUSTOM authenticators. When multiple CUSTOM authenticators are registered within the device or app, the type is not enough to distinguish between them (since all of them have CUSTOM type). In such case, the ID should be used. This is the ID that's provided by the authenticator developers. For PIN and FINGERPRINT authenticators, this value (while not empty) doesn't have much value.getName()
: Returns the name of the authenticator. For PIN and FINGERPRINT authenticators, names are predefined (PIN and Fingerprint). ForCUSTOM*
authenticators, the name is set in the client configuration provided by the IDAAS-core.isRegistered()
: This indicates if the authenticator was already registered for the user in the app. In particular, it will be always TRUE for PIN authenticator for any registered user.isPreferred()
: This indicates if the authenticator was set as preferred by the user. Only one (registered) authenticator can be set as preferred.
Registered and deregistered authenticators
To enable or disable each authenticator, the user has to register or deregister the authenticator.
If multiple user profiles are registered in the application, each user profile has its own set of registered authenticators. This means that if first user profile (Alice) registers fingerprint authenticator, the other registered user profile (Bob) does not register fingerprint authenticator.
The PIN authenticator is registered (created) during user registration. This type of authenticator can't be deregistered (unless the user gets deregistered). Other types of authenticators (FINGERPRINT and CUSTOM) can be registered and deregistered only by the currently authenticated user.
To fetch a set containing all possible authenticators for the user on current device, you can use the UserClient#getAllAuthenticators(final UserProfile userProfile)
method. The set will contain all registered and deregistered authenticators that are supported by the device and are enabled in the IDAAS-core configuration. You can also use the UserClientc#getRegisteredAuthenticators(final UserProfile userProfile)
and UserClient#getNotRegisteredAuthenticators(final UserProfile userProfile)
methods to fetch only registered or not registered authenticators.
Preferred authenticators
If a user has registered multiple authenticators, they can select a preferred authenticator. If a preferred authenticator is set, the preferred authenticator will be provided by default (the user retains the option to select an alternative authenticator.) If a preferred authenticator is deregistered, the Android SDK will provide the default PIN authenticator.
To set the preferred authenticator for the currently authenticated user, use the UserClient.setPreferredAuthenticator(final OneginiAuthenticator authenticator)
method.
- Only registered authenticators should be set as preferred.
- Only one authenticator can be set as preferred.
- Mobile authentication requests specify the authenticator that must be used. In these instances, the preferred authenticator setting is ignored.
Authenticate a user with a PIN
To authenticate a user with a PIN, determine if the user has registered and then handle the PIN authentication request.
Determine if a user exists
The UserClient
contains the getUserProfiles
method, which returns a set of all registered UserProfile
value objects. If the method isRegisteredAtLeastOneUser
returns false, it means no user is authenticated on the device. If the user is not registered, the user must register before they will be able to log in.
Example code - verify device has a registered user
Log in a registered user
If a user is registered on the device, you may use the UserClient
authenticateUser
method to attempt to authenticate that user. The authenticateUser
method requires the following arguments:
UserProfile
is theUserProfile
ValueObject
that you want to authenticate.OneginiAuthenticationHandler
is the authentication handler to return the authentication result to.
Authentication results in an access token, optionally with a refresh token. The authentication handler contains:
onSuccess
is the method that lets you know that authentication was finished successfully. At this point, you can request data on behalf of the user.onError
is the method that is called in every other case.
PIN request handlers
You need to provide your own authentication request handlers using the OneginiClientBuilder
methods. The OneginiCreatePinRequestHandler
and OneginiPinAuthenticationRequestHandler
are required in order to perform authentication flows with a PIN.
Example code
Create PIN request handler
The OneginiCreatePinRequestHandler
interface is responsible for handling the PIN creation process. Create a class that implements this interface and overrides the following methods:
-
startPinCreation(final UserProfile userProfile, final OneginiPinCallback oneginiPinCallback, final int pinLength)
: This method will be invoked by the Android SDK whenever there will be a need to create a new PIN (during registration, or during the change PIN action). You have to callOneginiPinCallback#acceptAuthenticationRequest(pinEnteredByUser)
in order to successfully finish the PIN creation process. ThepinLength
parameter determines the required pin length. In order to cancel the PIN creation process, you can call theOneginiPinCallback#denyAuthenticationRequest()
method. -
onNextPinCreationAttempt(final OneginiPinValidationError oneginiPinValidationError)
: This method will be called when the PIN provided by user hasn't met the PIN policy. You can check the exact error by comparing theOneginiPinValidationError#getErrorType()
value with theOneginiPinValidationError's
static fields. There are also theOneginiPinValidationError#getMessage()
andOneginiPinValidationError#getCause()
methods, which can return more information about the error. -
finishPinCreation()
is called whenever the correct PIN was created or the action was canceled by the user. Below is sample code for creating a custom PIN request handler. This example creates an additionalPinWithConfirmationHandler
to support the PIN verification step. You can feel free to skip this step if it's not relevant for your use case. You can check the full solution in our example app that is available on GitHub.
Example code
PIN authentication request handler
Create a class that implements the OneginiPinAuthenticationRequestHandler
interface, which is responsible for handling PIN authentication requests, and override the following methods:
-
startAuthentication(final UserProfile userProfile, final OneginiPinCallback oneginiPinCallback, final AuthenticationAttemptCounter attemptCounter)
: This method will be invoked by the Android SDK whenever there will be a to need authenticate the user. You have to callOneginiPinCallback#acceptAuthenticationRequest(pinEnteredByUser)
in order to successfully finish the PIN creation process orOneginiPinCallback#denyAuthenticationRequest()
to cancel it. -
onNextAuthenticationAttempt(final AuthenticationAttemptCounter attemptCounter)
: This method is called when the PIN that is provided by the user is incorrect, but the failed attempts limit hasn't been reached yet. The method's parameter is anAuthenticationAttemptCounter
object providing information about number of failed attempts, remaining attempts, and maximum attempts counters. -
finishAuthentication()
: This method is called whenever the authentication process is finished regardless of whether it was successful or failed.
Example code
Authenticate user with custom authenticator
The Android SDK allows you to authenticate users with third-party (custom) authenticators. In such case, you (or the custom authenticator library) are responsible for authenticating the user when requested and returning the authentication result (success, failure, or exception) back to the Android SDK. In order to use the custom authentication feature, you need to first enable and configure the feature on the IDAAS-core side.
To use a custom authenticator, you should provide an implementation of the OneginiCustomAuthenticator
interface to the Android SDK. The implementation provides the unique ID of an authenticator along with methods that should be called to register, deregister, or authenticate using the custom authenticator. These methods are named by the Android SDK as Actions
and are defined by interfaces: OneginiCustomAuthRegistrationAction
, OneginiCustomAuthDeregistrationAction
, and OneginiCustomAuthAuthenticationAction
.
Example code - for custom authentication implementation
OneginiCustomAuthRegistrationAction
The OneginiCustomAuthRegistrationAction
interface defines a method that should be called when the Android SDK requires the custom authenticator registration. When the OneginiCustomAuthRegistrationAction#finishRegistration
method is called, you should start the registration process and return the final result on the provided OneginiCustomAuthRegistrationCallback
. It consists of three methods:
-
void acceptRegistrationRequest(String optionalRegistrationData)
should be called when the custom authenticator registration has succeeded. -
void denyRegistrationRequest()
should be triggered when the custom authenticator registration has been canceled. -
void returnError(Exception e)
should be invoked when the custom authenticator registration has returned an error.
Example code - for custom authenticator registration action implementation
OneginiCustomAuthDeregistrationAction
The OneginiCustomAuthDeregistrationAction
interface defines a method that should be called when the Android SDK requires the custom authenticator deregistration. When the OneginiCustomAuthDeregistrationAction#finishDeregistration
method is called, you should start the deregistration process and return the final result on the provided OneginiCustomAuthDeregistrationCallback
. It consists of three methods:
-
void acceptDeregistrationRequest(String optionalDeregistrationData)
should be called when the custom authenticator deregistration has succeeded. -
void denyDeregistrationRequest()
should be triggered when the custom authenticator deregistration has been canceled. -
void returnError(Exception e)
should be invoked when the custom authenticator deregistration has returned an error.
Example code - for custom authenticator deregistration action implementation
OneginiCustomAuthAuthenticationAction
The OneginiCustomAuthAuthenticationAction
interface defines a method that should be called when the Android SDK requires the custom authenticator authentication. When the OneginiCustomAuthAuthenticationAction#finishAuthentication
method is called, you should start the authentication process and return the final result on the provided OneginiCustomAuthAuthenticationCallback
. It consists of two methods:
-
void returnSuccess(String optionalAuthenticationData)
should be called when the custom authenticator authentication has succeeded. -
void returnError(Exception e)
should be invoked when the custom authenticator authentication has failed.
Example code - for custom authenticator authentication action implementation
Authenticator handlers
The Android SDK provides two interfaces: OneginiCustomAuthenticationRequestHandler
for regular authentication, and OneginiMobileAuthWithPushCustomRequestHandler
for push authentication.
You will need to provide OneginiCustomAuthenticationRequestHandler
and OneginiMobileAuthWithPushCustomRequestHandler
to the OneginiClientBuilder
instance, together with the OneginiCustomAuthenticator
implementation, as shown below:
Example code - supply custom authenticator to the Android SDK
The OneginiCustomAuthenticationRequestHandler
interface exposes two methods you should use to control the process of authenticating the user:
-
void startAuthentication(UserProfile userProfile, OneginiCustomCallback callback)
is triggered when new custom authentication request is made, providing theUserProfile
object and the result callback. -
void finishAuthentication()
is triggered when custom authentication finished either with a success or an error.
OneginiMobileAuthWithPushCustomRequestHandler
works in exactly the same manner with a single change in the parameters of the startAuthentication()
method, where instead of the UserProfile
you get the OneginiMobileAuthenticationRequest
object containing information about the push request as well as the UserProfile
.
To control the flow of custom authentication, you should use the provided OneginiCustomCallback
. It consists of three methods:
-
acceptAuthenticationRequest()
should be called when the user accepts the custom authentication request. -
denyAuthenticationRequest()
should be triggered when the user denies the custom authentication request. -
fallbackToPin()
should be invoked when the user decides to resign from the custom authentication and wants to enter their PIN to finish the authentication.
Example code - for OneginiCustomAuthenticationRequestHandler implementation
Custom authenticator registration and authentication
To register the custom authenticator or authenticate with it, you should use the same methods like for other OneginiAuthenticators
: UserClient#registerAuthenticator(final OneginiAuthenticator authenticator, final OneginiAuthenticatorRegistrationHandler handler)
, UserClient#authenticateUser(final UserProfile userProfile, final OneginiAuthenticationHandler authenticationHandler)
, or UserClient#authenticateUser(final UserProfile userProfile, final OneginiAuthenticator oneginiAuthenticator, final OneginiAuthenticationHandler authenticationHandler)
.
Example code - custom authenticator registration
The only difference between the custom authenticator and other authenticator types (PIN, Fingerprint) is that in case of a custom authenticator, you can receive a non-null info object CustomInfo
in both successful and failed registration or authentication attempts. In case of a success, the object is passed as a param in the onSuccess()
method of the registration/authentication
attempt. In case of an error, the info object can be received by calling getErrorDetails().getCustomInfo()
methods on the error object.
The CustomInfo
contains the status code and the data that were returned by the registration or authentication script implemented in the extension engine.
Authenticate user with biometrics
Biometric authentication allows users to perform authentication by using a fingerprint or face recognition. Users are now enabled to access their sensitive data or authenticate transactions using Android's common biometric validation.
The Android SDK allows you to authenticate users with the biometric features of a user's device. You can use it for both regular authentication as well as mobile authentication. Users will be able to attempt biometric scanning as many times as the Android system will allow them to. If the Android Biometric API returns an error for any reason (for example when too many failed attempts are detected), the Android SDK will revoke biometric authentication and perform a fallback to PIN authentication.
Availability
A user can enable biometric authentication only if all of the following requirements are met:
- the device is not rooted
- the device supports Class 3 Biometrics (as defined by Android)
- the user has already enrolled biometrics on the device (that is, registered at least one fingerprint)
- the client configuration on the IDAAS-core allows using fingerprint authentication
Root detection
The root detection check is applied during the biometric authentication, even if root detection is disabled for the application itself. Rooted devices are more vulnerable as both the application sandbox and AndroidKeystore
can be violated.
Biometrics changes
Keys stored in the AndroidKeyStore
will become permanently invalidated once a new biometric enrollment is added or all enrollments are removed. In such case, the Android SDK will deregister biometric authenticator and the user will have to enroll for biometric authentication again.
Authenticate using Biometric Authentication
When biometric authentication is enabled and the device is not rooted, the user will be prompted to scan their finger instead of providing their PIN to authenticate. The Android SDK will use the OneginiBiometricAuthenticationRequestHandler
interface to ask for a fingerprint. The handler should show a Biometric Prompt and include BiometricPrompt.CryptoObject
. CryptoObject
is used for cryptography purposes and allows the Android SDK to use a biometric refresh token to authenticate the user.
If the biometric scan fails for any reason, the user can always choose to fall back on PIN authentication. After failing to scan a fingerprint for the allowed number of times, the Android SDK will automatically fall back on the PIN authentication method. This can be done by calling the OneginiBiometricCallback#fallbackToPin()
method.
Using biometric authentication with multiple user profiles
The Android SDK v5.03.00 introduced support for multiple user profiles. When this feature is implemented, a user will be able to create and use different accounts (profiles) on the same device. Each profile has its own separate PIN, push notification support, and other features.
If the application supports both the multiple profiles feature and biometric authentication, you should keep in mind that it has some (potential) drawbacks.
Let's assume that Bob is the owner of a device, but he shares it with his wife Alice. They have both registered their fingerprints and they both created profile in the ExampleApp. When the ExampleApp asks Bob for a fingerprint for login or to confirm a transaction, any valid (registered) fingerprint will be accepted. Because of that, Alice can log in to Bob's account using her fingerprint. When Bob tries to authenticate with a fingerprint, but the exceeds number of failed attempts, the Android Biometric API can be blocked automatically for some amount of time (around 15-30 seconds). If Alice tries to log in to her account shortly after that, she might not be able to do so before the API is unblocked. When the server detects improper usage of a biometric refresh token that indicates a corrupted or modified biometric keystore, all biometric refresh tokens on this device will be revoked on the server side.
Enabling biometric authentication
To enable biometric authentication for a user, you need to request a list of not yet registered authenticators with UserClient.getNotRegisteredAuthenticators(final UserProfile userProfile)
. This method can be used after the user is authenticated and will return a set of OneginiAuthenticator
that are possible to register. Then you can register the chosen authenticator providing the authenticator's instance to UserClient.registerAuthenticator(final OneginiAuthenticator authenticator, final OneginiAuthenticatorRegistrationHandler handler)
method, along with the handler that will inform you about the success or failure of the registration process. If your device hasn't met one of the requirements, the biometric authenticator won't be present in the list of authenticators.
Example code for registering a biometric authenticator
Disabling biometric authentication
To disable biometric authentication for the currently authenticated user profile, call deregisterAuthenticator(final OneginiAuthenticator authenticator, final OneginiAuthenticatorDeregistrationHandler handler)
on the UserClient
instance. The method will revoke user's biometric refresh token on both the client and server side.
The user will still be able to log in using their PIN.
Authenticator handlers
The Android SDK provides two OneginiCustomAuthenticationRequestHandler
interfaces for regular authentication and OneginiMobileAuthWithPushCustomRequestHandler
for push authentication.
You will need to provide OneginiCustomAuthenticationRequestHandler
and OneginiMobileAuthWithPushCustomRequestHandler
to the OneginiClientBuilder
instance, together with the OneginiCustomAuthenticator
implementation, as shown below:
Example code: supply a biometric authenticator
The OneginiBiometricAuthenticationRequestHandler
interface exposes two methods that are used to control the process of biometric authentication:
-
startAuthentication(final UserProfile userProfile, BiometricPrompt.CryptoObject cryptoObject, final OneginiBiometricCallback callback)
is triggered when a new fingerprint authentication request is made, providing anUserProfile
object, a biometric crypto object that has to be authenticated, and a biometric callback. -
finishAuthentication()
is triggered when biometric authentication finished either with success or an error.
The OneginiMobileAuthWithPushFingerprintRequestHandler
works in exactly the same manner with a single change in the parameters of the startAuthentication()
method, where instead of the UserProfile
you get the OneginiMobileAuthenticationRequest
object containing information about the push request as well as the UserProfile
.
Example code for OneginiBiometricAuthenticationRequestHandler implementation
OneginiBiometricCallback
To control the flow of biometric authentication you should use the OneginiBiometricCallback
callback. It consists of four methods:
-
userAuthenticatedSuccessfully()
should be called when a user successfully authenticated using a Biometric Prompt. -
denyAuthenticationRequest
should be triggered when a user denies the biometric authentication request. -
fallbackToPin
should be invoked when a user decides to resign from biometric authentication and wants to enter their PIN to finish authentication. -
onBiometricAuthenticationError(final int errorCode)
should be called when the Biometric Prompt returned an error. TheerrorCode
parameter represents the code returned from the Biometric Prompt. Based on the code, the Android SDK will perform the necessary actions, such as when abuse is detected, biometric authenticator will be deregistered for all users.
In the example code above you should use the static instance of OneginiBiometricCallback
in the BiometricActivity
and BiometricPrompt.CryptoObject
to react to user actions.
Showing biometric prompt
The Android SDK depends on the androidx.biometric:biometric
library to provide this functionality. When implementing a BiometricPrompt
, it's important to import classes from the androidx.biometric
package and not from android.hardware.biometrics
. For the library version used by the Android SDK, check third-party libraries.
To perform biometric authentication you first need to build the PromptInfo
with the correct parameters:
and then display the prompt to the user.
In the authenticate method of the BiometricPrompt
, you need to provide the previously built PromptInfo
object as well as the BiometricPrompt.CryptoObject
you received in the OneginiBiometricAuthenticationRequestHandler.startAuthentication(final UserProfile userProfile, BiometricPrompt.CryptoObject cryptoObject, final OneginiBiometricCallback callback)
method.
BiometricPrompt
required also a callback object in which you will receive the authentication result. This result needs to be passed back to the Android SDK via OneginiBiometricCallback
to finish the process.