MFA SDK - Mobile (Android)
TrustBuilder Safe-T SDK for mobile enables the integration of MFA capabilities into a mobile app.
It provides a set of functions that allow applications to manage authentication and transaction confirmation flows.
The SDK exposes the following functionalities:
Validate an authentication request
Confirm a transaction
Retrieve pending operations requiring user action
Reject an operation
Register a secure token for a given login
Generate an activation code to register a new secure token
Update the push notification identifier (Push ID) of the device
Retrieve secure tokens stored locally on the device
Change secret code
Reset a blocked secret code
Generate a reset code
Change the display name of a secure token
The SDK also provides in-app MFA interactions, allowing authentication and transaction flows to be handled directly within the application UI:
Request authorization for authentication or transaction confirmation within the app
Validate an authentication request in-app
Confirm a transaction in-app
Register biometric authentication as a secure factor
This integration guide uses specific terms:
Device
The device represents the possession factor of the user. It refers to the mobile device on which the application and secure token are installed.
Secure Token
A cryptographic object stored on a registered device that enables authentication.
Transaction confirmation
A process where the user explicitly approves a transaction in its specific context. The generated authentication code binds the transaction context to the user’s credentials, making it unforgeable and usable as a proof of consent.
Requirements
Download TrustBuilder sample app for Android
Latest version of Android Studio
JDK 17 or later
Minimum SDK : Android API 26 (Android 8.0 Oreo) or higher
Target SDK: Android API 35
The mobile application must be registered as a custom application in TrustBuilder administration console. You should provide Service Account JSON and Application ID to administrator. Once the application is registered in the TrustBuilder system an App Alias is automatically generated. It is required during SDK initialization.
Installation
Gradle dependency: in your app-level
build.gradle, add the TrustBuilder MFA library to your dependencies:CODEdependencies { implementation 'io.trustbuilder.mfa:trustbuilder-mfa-lib:latest.integration' }Sample application configuration: create a
local.propertiesfile at the project root:CODEappAlias=<your_app_alias> appName=<your_app_name> appId=com.xxxx.xxxxxxxappAlias-> the unique identifier of the custom application declared in TrustBuilder console (See Requirements)appName-> the display name of the application.appId→ the Android application ID.
Security Best Practices
The following practices are implemented in the sample application and are strongly recommended.
Source: Android developers security best practices
Push notifications (Firebase Cloud Messaging)
Firebase Messaging is a solution used to send remote push notifications across Android, iOS and web devices. It allows both background and in-app notifications.
Firebase project setup
Create a project at https://console.firebase.google.com.
Add your Android application (with its package name).
If your app uses many different package names you should create one for each.Download the
google-services.jsonfile and place it in yourapp/module.Check that
google()is listed in your top-levelbuild.gradlerepositories.
Firebase dependency
You should add the Firebase dependencies in your build.gradle file:
// Top-level build.gradle
plugins {
id 'com.google.gms.google-services' version '...' apply false
}
// app/build.gradle
plugins {
id 'com.google.gms.google-services'
}
dependencies {
implementation platform('com.google.firebase:firebase-bom:34.2.0')
implementation 'com.google.firebase:firebase-messaging'
}
Handling notifications
In-app notifications → You should create a class that will extend FirebaseMessagingService and implement the
onMessageReceivedmethod. It will be the entry point for every notifications received when the app is in foreground. Then add the service in the AndroidManifest.xml.Background notifications → To handle background notifications, you should use the data messages only. The data messages are handle within the service extending FirebaseMessagingService. Note that if you use notification messages or messages with both notification and data payload, the
onMessageReceivedmethod will not handle the background notifications (more information).
See how FirebaseMessagingService extension is implemented in the sample app we provide:
CODEpublic class PushNotificationReceiveService extends FirebaseMessagingService { private static final MutableLiveData<Map<String, String>> IN_APP_MESSAGE = new MutableLiveData<>(); private static final MutableLiveData<String> TOKEN = new MutableLiveData<>(); public static MutableLiveData<Map<String, String>> getInAppMessage() { return IN_APP_MESSAGE; } public static MutableLiveData<String> getNewToken() { return TOKEN; } @Override public void onMessageReceived(RemoteMessage remoteMessage) { IN_APP_MESSAGE.postValue(remoteMessage.getData()); } @Override public void onNewToken(@NonNull String token) { super.onNewToken(token); TOKEN.postValue(token); } }CODE<service android:name=".utils.PushNotificationReceiveService" android:enabled="true" android:exported="false"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service>
Runtime permission (Android 13+)
For your app to send non-exempt notifications, the user must grant this permission to your app.
More information
Declare the following permission in your app’s AndroidManifest file:
CODE<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />Request it at runtime in
onResume:CODEif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS); } }
Create and show the notification
In your app’s MainActivity file, set the notification content, the notification channel and show the notification (more information). In our sample app, this is implemented in the showNotification method.
FCM token refresh
Implement an FCM token change observer to detect a possible PushID change (in-case of user’s device change for example).
PushNotificationReceiveService.getNewToken().observe(this, token -> {
if (token != null) {
// Call pushIdRegistration use case with the new token
}
});
Initialization
There are two interfaces to implement:
Implementing
IHostinterfaceIHostdescribes general properties of the host application and device:CODEpublic class ConfigHost implements IHost { @Override public String getSerial() { return Settings.Secure.ANDROID_ID; } @Override public String getName() { return BuildConfig.APPLICATION_NAME; } @Override public SecureTokenTypeEnum getTknType() { return SecureTokenTypeEnum.MOBILE; } @Override public String getAppAlias() { return BuildConfig.APP_ALIAS; } @Override public ApplicationInfo getAppInfo() { return ApplicationInfo.builder() .id(BuildConfig.APPLICATION_ID) .name(BuildConfig.APPLICATION_NAME) .version(BuildConfig.VERSION_NAME) .type(BuildConfig.BUILD_TYPE) .build(); } @Override public OsInfo getOsInfo() { return OsInfo.builder() .name("Android") .version(String.valueOf(Build.VERSION.RELEASE)) .build(); } }serial: Hardware serial (useSettings.Secure.ANDROID_ID)name: Display name of the applicationtype: Token type - alwaysSecureTokenTypeEnum.MOBILEfor AndroidappAlias: Custom application alias (see Requirements)appInfo.id: application IDappInfo.name: Name of the applicationappInfo.version: Version of the applicationappInfo.type: Build type (debug / release)osInfo.name: OS name ("Android")osInfo.version: Android version string
Implementing
ISecureTokenStorageinterfaceISecureTokenStorageprovides save, retrieve, list and remove operations forSecureTokenobjects. The sample application stores tokens as AES-GCM encrypted JSON files in the app's internal storage (context.getFilesDir()), with the initialization vector stored inSharedPreferences.
Function | Input | Returns | Description |
|---|---|---|---|
|
| — | Backup of the secure token |
|
|
| Retrieves one secure token by alias |
| — |
| Returns all stored tokens |
|
|
| Deletes a token |
Creating the library instance
TheTrustBuilderMfaLibinstance should be a singleton, created once and reused across activities:
public class TrustBuilderMfaLibHolder {
private static TrustBuilderMfaLib instance;
public static TrustBuilderMfaLib getInstance(Activity activity) {
if (instance == null) {
ConfigHost host = ConfigHost.getInstance();
ConfigSecureTokenStorage storage = ConfigSecureTokenStorage.getInstance(activity);
instance = new TrustBuilderMfaLib(host, storage);
}
return instance;
}
}
General principles
Use Case pattern
The SDK exposes its features as use cases. There are two types:
<SingleUseCase> → one-step use case: it exposes a single
executefunction to process it.<UseCase> → two-step use case: it exposes two functions
setupandexecuteto process it. This allows the management of data to be entered or read by the user (typically user credentials management).
The naming format of the methods exposed by the TrustBuilder MFA library looks like this:
TrustBuilderMfaLib mfaLib = TrustBuilderMfaLibHolder.getInstance(activity);
// SingleUseCase example
MyUseCase usecase = mfaLib.startMyUseCase(params);
MyUseCaseResult result = usecase.execute();
// UseCase example
MyUseCase usecase = mfaLib.startMyUseCase(params);
MyUseCaseSetupResult setupResult = usecase.setup();
// → collect credential from user
MyUseCaseResult result = usecase.execute();
Authentication flow
There are two authentication flows:
Out-Of-Band → the authentication request is initiated from a web channel and validated on the mobile.
In-App → the authentication request is initiated from the current application and validated in the current application.
Some exposed methods are different depending on the flow type.
Features implementation
This section describes the features implemented in the sample application available in the TrustBuilder MFA Android SDK.
Validate an authentication request
Out-Of-Band authentication
Use case name | authentication |
|---|---|
Use case type | Use case |
Description | Authenticate a user: this generates a One-Time-Password and calls TrustBuilder server to validate it. |
Input parameter(s) |
|
Errors |
|
Example |
JAVA
See the source code of the sample application |
In-App authentication
Use case name | inAppAuthentication |
|---|---|
Use case type | UseCase |
Description | Authenticate a user in the current application. This generates a token if the authentication is successful. IN-APP |
Input parameter(s) |
|
Errors |
|
Example |
JAVA
See the source code of the sample application |
Activate a Secure Token
Use case name | secureTokenEnrollment |
|---|---|
Use case type | Use case |
Description | Activate a Secure Token for a given login (enrollment process) |
Input parameter(s) |
|
Errors |
|
Example |
JAVA
See the source code of the sample application |
Retrieve all Secure Tokens
Use case name | secureTokensListing |
|---|---|
Use case type | SingleUseCase |
Description | Retrieve the secure tokens stocked in the local storage |
Input parameter(s) | / |
Errors |
|
Example |
JAVA
See the source code of the sample application |
Retrieve the pending operations
Use case name | pendingAuthSessionsRetrieval |
|---|---|
Use case type | SingleUseCase |
Description | Retrieve the pending operations |
Input parameter(s) |
|
Errors |
|
Example |
JAVA
See the source code of the sample application |
Reject an operation
Use case name | authSessionCancellation |
|---|---|
Use case type | SingleUseCase |
Description | Reject an authentication request or a transaction confirmation request |
Input parameter(s) |
|
Errors |
|
Example |
JAVA
See the source code of the sample application |
Confirm a transaction
Out-Of-Band transaction
Use case name | sealing |
|---|---|
Use case type | UseCase |
Description | Confirm an electronic transaction on top of authentication. This displays the business data provided by the Service Provider. Then this generates One-Time-Password and calls TrustBuilder server to validate it. |
Input parameter(s) |
|
Errors |
|
Example |
JAVA
See the source code of the sample application |
In-App transaction
Use case name | inAppSealing |
|---|---|
Use case type | UseCase |
Description | Confirm an electronic transaction on top of authentication in the current application. This generates a token if the authentication is successful. IN-APP |
Input parameter(s) |
|
Errors |
|
Example |
JAVA
See the source code of the sample application |
Request an authorization
Use case name | authorizeRequest |
|---|---|
Use case type | SingleUseCase |
Description | Request an authorization for an in-app authentication or for an in-app transaction confirmation. It will provide a sessionId to execute the requested operation. IN-APP |
Input parameter(s) |
|
Errors |
|
Example |
JAVA
See the source code of the sample application |
Generate an activation code
Use case name | activationCodeGeneration |
|---|---|
Use case type | UseCase |
Description | Generate an activation code to activate a new Secure Token |
Input parameter(s) |
|
Errors |
|
Example |
JAVA
See the source code of the sample application |
Change Secret Code
Use case name | secretCodeChange |
|---|---|
Use case type | UseCase |
Description | Change a secret code (the user knows the current secret code but wants to change its value) |
Input parameter(s) |
|
Errors |
|
Example |
JAVA
See the source code of the sample application |
Reset a Secret code
Use case name | secretCodeReset |
|---|---|
Use case type | UseCase |
Description | Reset a blocked secret code |
Input parameter(s) |
|
Errors |
|
Example |
JAVA
See the source code of the sample application |
Generate a Reset code
Use case name | resetCodeGeneration |
|---|---|
Use case type | SingleUseCase |
Description | Generate a reset code and send it by email to the user An error is returned:
|
Input parameter(s) |
|
Errors |
|
Example |
JAVA
See the source code of the sample application |
Change the Secure token name
Use case name | secureTokenFriendlyNameUpdate |
|---|---|
Use case type | SingleUseCase |
Description | Update the name of the secure token |
Input parameter(s) |
|
Errors |
|
Example |
JAVA
See the source code of the sample application |
Update the push ID
Use case name | pushIdRegistration |
|---|---|
Use case type | SingleUseCase |
Description | Update the push ID generated for the host application |
Input parameter(s) |
|
Errors |
|
Example |
JAVA
See the source code of the sample application |
Register a biometric factor
Use case name | BiokeyRegistration |
|---|---|
Use case type | UseCase |
Description | Register biometric data. A key pair is generated in the keystore to be used on a successful biometric matching on the trusted device. The public key is provided to the back-end for verifications of challenges signature during authentication. |
Input parameter(s) |
|
Errors |
|
Example |
JAVA
See the source code of the sample application |
Data Types
Data | Description | Parameters |
|---|---|---|
CredentialProvider | Object containing the information needed to request a credential from the user |
|
CredValue | Object containing the credential data |
|
CredType | Credential type |
|
BoolResult | Object encapsulating a Boolean |
|
SecureToken | Data of a secure token exposed by the library |
|
AuthSession | Data of an authentication session or a sealing session |
|
AuthorizeScope | Enumeration describing the use of the authorization request | Possible values:
|
AuthScope | Enumeration describing the scope of an authentication | Possible values:
|