Mobile SDK: Android

This page will show you how to install and use the FuturaeKit SDK for Android.

Prerequisites

Before reading the rest of this guide, please make sure that you first read the Mobile SDK: Introduction page.

Release Information

You can find information about the Android FuturaeKit SDK release history and changes here.

Migrate from SDK v1.x.x

Assuming that your app already integrates SDK 1.x.x, the steps to migrate to the latest version v2.x.x, which features the User Presence Verification mechanism, are described below:

  1. Update the SDK version to 2.x.x in your build.gradle file, or for manual installations, get the latest SDK 2.x.x from the SDK repository.
  2. Refactor your app code according to the examples provided across this guide, paying special attention to:
  • Update your SDK launch method and add the new SDK configuration settings, according to the example in the Initialize the SDK section.
  • The FuturaeSDK instance getter is now FuturaeSDK.getClient() for Kotlin and FuturaeSDK.INSTANCE.getClient() for Java.
  • The Account class was replaced by the FTAccount class, therefore your app needs to be updated accordingly. Please refer to the Account status section.
  1. Then launch the SDK using the LockConfigurationType as NONE. After launching the SDK with LockConfigurationType.NONE, all the previous data from SDK v1.x.x including accounts and keys will remain valid.
  2. If you wish to use a different LockConfigurationType, then the SDK must be reset, and initialized again with the new configuration. After resetting the SDK, all the accounts, keys and existing SDK configuration will be lost, and the SDK will need to be re-activated by enrolling again the relevant user accounts. Also note that before calling an SDK protected function, user presence must be verified using an SDK unlock function.

Installation

We are going to assume that you are using Android Studio for your development. You can install FuturaeKit into your project using:

Maven

The preferred way to get the FuturaeKit SDK for Android is through maven and the Futurae private repository.

To do so add the following lines to your build.gradle file:

repositories {
  maven {
    url 'https://artifactory.futurae.com/artifactory/futurae-mobile'
    credentials {
      username = 'anonymous'
      password = ''
    }
  }
}

dependencies {
  implementation('com.futurae.sdk:futuraekit:x.x.x')
}

Of course, make sure to specify the desired version number, in place of x.x.x.

Manual Installation

You can download the latest SDK from the SDK repository, or clone the repository directly. The repository also contains a sample demo app to show how the SDK can be integrated.

To integrate the FuturaeKit SDK into your project, copy futuraekit.aar into the src/main/libs folder of your app. Then, in your module’s build.gradle (the one under “app”), add the following dependencies:

implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-moshi:2.9.0'
implementation 'com.squareup.moshi:moshi-adapters:1.6.0'
implementation "com.squareup.moshi:moshi-kotlin:1.6.0"
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
implementation 'com.github.nisrulz:easydeviceinfo-base:2.4.1'
implementation 'com.google.code.gson:gson:2.8.9'
implementation "androidx.biometric:biometric:1.1.0"
implementation "androidx.security:security-crypto:1.0.0"
implementation "com.nimbusds:nimbus-jose-jwt:7.8.1"

android_sdk_gradle_app

And in the projects build.gradle adjust the repositories to include the libs folder:

allprojects {
  repositories {
    google()
    jcenter()
    flatDir {
      dirs 'src/main/libs'
    }
  }
}

android_sdk_gradle_project

Configuration and Initialization

To configure and initialize the SDK, take the following steps:

Add Permissions

Please add the following permissions, which the FuturaeKit SDK needs, if they are not already present in your AndroidManifest.xml file:

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

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />

<meta-data
    android:name="com.google.android.gms.vision.DEPENDENCIES"
    android:value="barcode"/>

Initialize the SDK

We recommend using an android Application class to initialize the SDK. If you already have one in your app, follow these steps:

Firstly, in your Application class find or create the onCreate method and add the following code to initialize the FuturaeKit SDK:

import com.futurae.sdk.FuturaeSDK;

public class AppMain extends Application {

  // overrides
  @Override
  public final void onCreate() {
    super.onCreate();

      //launch SDK with the specified configuration
      FuturaeSDK.INSTANCE.launch(this,new SDKConfiguration.Builder(this)
           .setLockConfigurationType(LockConfigurationType.BIOMETRICS_ONLY)
           .setUnlockDuration(5)
           .setInvalidatedByBiometricChange(true)
           .build());
  }    
}

Once the SDK is initialized, you may access the SDK instance and functions using the SDK getClient() getter:

FuturaeSDK.getClient()

Secondly, in your res/values folder make sure to create a file futurae.xml with the following contents:

<?xml version="1.0" encoding="utf-8"?>
<resources>

  <string name="ftr_sdk_id">{FuturaeSdkId}</string>
  <string name="ftr_sdk_key">{FuturaeSdkKey}</string>
  <string name="ftr_base_url">https://api.futurae.com:443</string>

</resources>

You can get your SDK credentials from Futurae Admin:

  • First you need to choose or determine the Futurae Service which is configured in your backend application.
  • Assuming you can access the particular Service on Futurae Admin, you can go to Settings -> Mobile SDK in order to get your SDK credentials
  • If Mobile SDK is not enabled for the particular Service, please contact Futurae Support in order to enable it.

Build your App

Build and run your app. If it is successful, you should be able to see the SDK logs in the console.

Configure R8 and ProGuard

In case you are installing the SDK manually and using R8 or ProGuard to obfuscate your app, you need to include the proguard rules of the proguard-rules.pro file. Please see the build.gradle file of the FuturaeDemo app, as an example on how to do this.

Demo App

The SDK’s repository contains a stripped-down demo app which showcases examples of how some of the SDK’s core features can be integrated.

Features

The FuturaeKit SDK for Android provides the following features and functionality:

Callbacks

The SDK methods that perform API calls to the Futurae backend use callbacks as the feedback mechanism. These calls expect an object of the FuturaeCallback interface as an argument:

public interface FuturaeCallback {
  void success();
  void failure(Throwable throwable);
}

The following callback interface is used as an argument to the user SDK unlock functions, to handle the function outcome:

interface Callback<T> {

    fun onSuccess(result : T)

    fun onError(throwable: Throwable)

}

Push notifications

Your app must be set up to receive Firebase Cloud Messaging (FCM) push notifications from the Futurae backend. You can choose to receive and handle these notifications yourself, or alternatively you can use the existing infrastructure provided in the SDK. You can find more information on how to setup FCM push notifications for your app in the Firebase Cloud Messaging Developer Guide.

In order to be able to receive FCM notifications, you need to specify the Firebase Messaging service inside the application section of your Manifest:

<service android:name="com.futurae.sdk.messaging.FTRFcmMessagingService">
  <intent-filter>
    <action android:name="com.google.firebase.MESSAGING_EVENT" />
  </intent-filter>
</service>

For this purpose, you can either use the one included in the SDK (com.futurae.sdk.messaging.FTRFcmMessagingService), or write your own. This service overrides two important methods:

@Override
public void onNewToken(String token);

@Override
public void onMessageReceived(RemoteMessage message);

The first one is invoked whenever a new FCM push token has been generated for the app; it is important to register this token with the Futurae backend in order to continue receiving push notifications. The FTRFcmMessagingService implements this functionality.

The second one is invoked whenever a new push notification (or cloud message) is received by the app. The FTRFcmMessagingService then processes this message and invokes the SDK accordingly.

FCM token registration

The FTRFcmMessagingService is responsible for registering the app’s FCM token to the Futurae server. This is important for the server to be able to issue FCM notifications for your app. The provided service handles this, however if you need to, you can write your own or extend the existing one.

If you are implementing your own FCM notification handling, you should register the FCM token to the Futurae server every time it changes. The call that registers the FCM token to the Futurae server is registerPushToken() , and it is necessary every time the FCM token is generated or is changed by FCM.

For example, once the app receives a new FCM token (e.g. via an onNewToken() callback in your own FirebaseMessagingService subclass), the token needs to be obtained and registered to the Futurae server using the following code:

FuturaeSDK.getClient().registerPushToken(fcmToken, new FuturaeCallback() {
  @Override
  public void success() {

  }

  @Override
  public void failure(Throwable t) {

  }
});

FCM listener service

The FTRFcmMessagingService receives FCM push notifications and handles them, according to the actions dictated by the Futurae server. You can use or extend the service provided by the SDK, or write your own. There are two distinct push notification types issued by the Futurae server: Aprove or Unenroll.

In case you want to process and handle the FCM notifications without using FTRFcmMessagingService, you must use the following code in order to process and handle the notifications sent by the Futurae server, inside the implementation of your own FirebaseMessagingService subclass:

@Override
public void onMessageReceived(RemoteMessage message) {

  // Create and handle a Futurae notification, containing a Bundle with any data from message.getData()
  FTRNotification notification = FTRNotificationFactory.createNotification(service, data);
  notification.handle();
}

Local intents

Once a Futurae FCM notification has been handled, the SDK will notify the host app using local broadcasts. The app should register a broadcast receiver for these intents and react accordingly. There are three distinct Intents that the notification handlers might send in a local broadcast:

  • INTENT_GENERIC_NOTIFICATION_ERROR: Indicates that an error was encountered during the processing or handling of a FCM notification.
  • INTENT_APPROVE_AUTH_MESSAGE: Indicates that a One-Touch athentication attempt has been initiated.
  • INTENT_ACCOUNT_UNENROLL_MESSAGE: Indicates that a user account has been logged out remotely.

The following example shows how to register for these intents:

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(NotificationUtils.INTENT_GENERIC_NOTIFICATION_ERROR);  // General notification error intent
intentFilter.addAction(NotificationUtils.INTENT_APPROVE_AUTH_MESSAGE);        // Approve authentication notification intent
intentFilter.addAction(NotificationUtils.INTENT_ACCOUNT_UNENROLL_MESSAGE);    // Logout user notification intent

LocalBroadcastManager.getInstance(getContext()).registerReceiver(new BroadcastReceiver() {

  @Override
  public void onReceive(Context context, Intent intent) {

    switch(intent.getAction()) {
      case NotificationUtils.INTENT_ACCOUNT_UNENROLL_MESSAGE:
        // Handle unenroll notification (e.g. refresh lists)
        break;

      case NotificationUtils.INTENT_APPROVE_AUTH_MESSAGE:
        // Handle approve notification (e.g. show approve view)
        break;

      case NotificationUtils.INTENT_GENERIC_NOTIFICATION_ERROR:
        // Handle FCM notification error
        break;
    }
  }
}, intentFilter);

User presence verification

User presence verification enhances security by requiring the Futurae SDK to be unlocked by verifying user presence, before certain protected SDK operations can be performed. User presence can be verified by leveraging Class 3 Strong biometrics (e.g., fingerprint, iris, or face recognition), device credentials (e.g. PIN, pattern, or password) or an SDK PIN (also known as Custom App PIN), set by the user upon the first enrollment, with the purpose of verifying the user identity to unlock the SDK methods that are protected by the user presence verification mechanism.

The Futurae SDK provides a set of options which can be configured during the Initialize the SDK step, in order to control the behavior of the user presence verification mechanism.

setLockConfigurationType() - This function sets the user presence verification lock configuration type between the following options:

  • NONE - The SDK will not use any lock mechanism, therefore user presence verification will not be enforced. This is the default value in case that a lock configuration type is not set. This option must be used when launching the SDK for the first time, after migrating from a previous SDK v1.x.x install.
  • BIOMETRICS_ONLY - This lock configuration type allows the end user to only unlock the SDK through strong biometric authentication.
  • BIOMETRICS_OR_DEVICE_CREDENTIALS - The SDK can be unlocked by authenticating either using biometrics or device credentials.
  • SDK_PIN_WITH_BIOMETRICS_OPTIONAL - Allows the user to perform user presence verification by authenticating with an SDK-specific PIN or with biometrics. In this case, the user is required to set an SDK PIN (upon the first enrollment), which will be stored and verified on the server side. On top of that, the user may choose to enable and use biometric authentication, as a means of convenience. This SDK configuration implies a server-side validation of the SDK PIN, even when using biometric verification, therefore the device must have network connectivity. Nevertheless, when configured with this lock configuration type, the SDK provides functionality which can be used to authenticate the user even when the device is offline, such as the methods describe in the sections TOTP and offline QR code.

setUnlockDuration() - Sets the duration in seconds that the SDK remains unlocked for, after successfully calling an unlock method. The accepted value range is between 2 and 300 seconds, and configuring any value out of this range will raise an exception. If the unlock duration is not set, then the SDK will assume a default value of 60 seconds.

setInvalidatedByBiometricChange() - If set to true, any change in the device biometrics settings will result in the user presence verification mechanism being invalidated, rendering most of the SDK functions unavailable. The steps to reinstate the user presence verification mechanism vary according to the configured lock configuration type:

  • SDK_PIN_WITH_BIOMETRICS_OPTIONAL - The app can either re-activate biometrics or reset and initialize the SDK again.
  • For the remaning lock configuration types, the only option is to reset and initialize the SDK.

Verify user presence with biometrics

The Futurae SDK can be unlocked by performing biometrics verification. After calling the unlockWithBiometrics() method, the OS will display a biometric prompt to authenticate the user and, if the verification is successful, the SDK will be unlocked for the configured period.

The unlockWithBiometrics method can be used when the SDK configured lock mechanism type is BIOMETRICS_ONLY or SDK_PIN_WITH_BIOMETRICS_OPTIONAL. When the SDK configured lock mechanism is SDK_PIN_WITH_BIOMETRICS_OPTIONAL, a server-side verification of the SDK PIN takes place, therefore network connectivity is required.

FuturaeSDK.getClient().unlockWithBiometrics(
  //the activity that will present the Biometrics prompt to the user
  requireActivity(),

  //the title used of the Biometrics prompt
  "Unlock SDK",

  //the subtitle used for the Biometrics prompt
  "Authenticate with biometrics",
  
  //the description used for the Biometrics prompt 
  "Authentication is required to unlock SDK operations",
  
  //the text for the “cancel” button of the Biometrics prompt
  "cancel",
  
  //callback used to receive the response of the unlock request
  object : Callback<Unit> {
    override fun onSuccess(result: Unit) {
      //user presence successfully verified
    }
    override fun onError(throwable: Throwable) {
      //user presence verification failed
      showErrorAlert("SDK Unlock", throwable)
    }
 }
)

Verify user presence with biometrics or device credentials

if the SDK setLockConfigurationType is set as BIOMETRICS_OR_DEVICE_CREDENTIALS, user presence can be verified using biometrics, providing that the SDK biometrics verification is active. If biometrics verification is not active, the SDK will automatically proceed with user presence verification using the configured device credentials, such as the device PIN.

The method unlockWithBiometricsDeviceCredentials() will attempt to verify user presence preferentially using biometrics, when the conditions described in the section SDK biometrics configuration are met, or alternatively using the configured device credentials.

FuturaeSDK.getClient().unlockWithBiometricsDeviceCredentials(
  //the activity that will present the authentication prompt to the user
  requireActivity(),

  //the title used of the authentication prompt
  "Unlock SDK",

  //the subtitle used for the authentication prompt
  "Authenticate with biometrics or device credentials",
  
  //the description used for the authentication prompt 
  "Authentication is required to unlock SDK operations",
  
  //callback used to receive the response of the unlock request
  object : Callback<Unit> {
    override fun onSuccess(result: Unit) {
      //user presence successfully verified
    }
    override fun onError(throwable: Throwable) {
      //user presence verification failed
      showErrorAlert("SDK Unlock", throwable)
    }
  }
)

Verify user presence with SDK PIN or biometrics

User presence can also be verified using an SDK PIN, which is an alphanumeric password that the user configures in the app by the time that the first account is activated, and it may then be used as a user presence verification mechanism.

In this case, the app needs to implement the relevant mechanism to ask the user to supply the SDK PIN and then invoke the function unlockWithSDKPin() by providing the PIN supplied by the user. After successfully verifying the SDK PIN, the SDK will remain unlocked for the configured unlock period.

Unlocking the SDK with an SDK PIN is only available if the configured lock configuration type is SDK_PIN_WITH_BIOMETRICS_OPTIONAL and after the user complete the first enrollment and setup the SDK PIN.

This unlock method requires a server-side verification of the SDK PIN, therefore the device must have network connectivity for the operation to be completed successfully. Moreover, the user can choose to enable the SDK biometrics authentication, as a means of convenience. When the SDK biometrics verification is enabled, user presence can be additionally verified using biometrics, besides using the SDK PIN.

FuturaeSDK.getClient().unlockWithSDKPin(
  //the SDK PIN inserted by the user
  sdkPin,

  //callback used to receive the response of the unlock request
  object : Callback<Unit> {
    override fun onSuccess(result: Unit) {
      //user presence successfully verified
    }
    override fun onError(throwable: Throwable) {
      //user presence verification failed
      showErrorAlert("SDK Unlock", throwable)
    }
  }
)

Lock SDK

It is advised that the app locks the SDK after an operation finishes as well as when the app is in a state where it would have its security compromised, for instance when it is moved to the background. The SDK may be immediately locked by calling the lock() function.

FuturaeSDK.getClient().lock()

Performing a successful user verification will unlock the SDK for the configured unlockDuration passed as an argument during initialization. It’s recommended that the app locks the SDK right after the completing the protected operation to which it was unlocked for, instead of waiting the configure unlockDuration to expire leading the SDK to be automatically locked.

Once locked, the SDK will need to be unlocked again via user presence verification as described above and depending on the selected lock configuration type.

Check if the SDK is locked

At any point in time you can check the locked status of the SDK by calling the method isLocked().

if (FuturaeSDK.getClient().isLocked()) {
  //Unlock SDK before calling a protected method
}

Get SDK unlock methods

The SDK provides functionality for the app to query the available methods which can be used to perform user verfication and consequently unlock the SDK. Calling the method getActiveUnlockMethods returns a list of UnlockMethodType enum values that the SDK can currently be unlocked with:

FuturaeSDK.getClient().activeUnlockMethods.joinToString()

enum UnlockMethodType {
     BIOMETRICS,
     BIOMETRICS_OR_DEVICE_CREDENTIALS,
     SDK_PIN
}

QR codes

The Futurae Authentication platform, uses QR codes for different operations:

  • Enroll a device for a user (online)
  • Authenticate a user or transaction (online)
  • Authenticate a user or transaction (offline)

The Futurae SDK supports all these functionalities. The business App can have different flows for supporting the needed functionality, or condense all QR Code operations in one. The Futurae SDK provides a handy method to identify on the fly which type of QR Code the user has scanned:

Barcode qrcode = data.getParcelableExtra(FTRQRCodeActivity.PARAM_BARCODE);
switch (FuturaeClient.getQRCodeType(qrcode.rawValue)) {
  case FuturaeClient.QR_ENROLL:
    // handle Enroll QR Code
    break;
  case FuturaeClient.QR_ONLINE:
    // handle Online QR Code Factor
    break;
  case FuturaeClient.QR_OFFLINE:
    // handle Offline QR Code Factor
    break;
}

Enroll

To enroll this SDK as a device for a Futurae User, call the enroll() method using a valid activation code, for example obtained by scanning an enrollment QR Code:

startActivityForResult(FTRQRCodeActivity.getIntent(this), FTRQRCodeActivity.RESULT_BARCODE);

If a QR Code is successfully scanned then onActivityResult will be called, with the scanned code:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {

  if (resultCode == RESULT_OK && requestCode == FTRQRCodeActivity.RESULT_BARCODE) {

    //you may use this or any other function to scan the QR code
    Barcode qrcode = data.getParcelableExtra(FTRQRCodeActivity.PARAM_BARCODE);

    //first, make sure the SDK is unlocked, then proceed

    FuturaeSDK.getClient().enroll(qrcode.rawValue, new FuturaeCallback() {
      @Override
      public void success() {

      }

      @Override
      public void failure(Throwable throwable) {

      }
    });
  }

}

Please make sure to call enroll, inside the onActivityResult method to complete the user enrollment.

Enroll and setup the SDK PIN

When the SDK lock configuration type is SDK_PIN_WITH_BIOMETRICS_OPTIONAL, the user must set the SDK PIN upon the first enrollment, therefore the activation of the first account is perfomed by calling the SDK method enrollAndSetupSDKPin instead, and providing as argument the PIN inserted by the user.

The app must implement the necessary mechanism to ask the user to insert the SDK PIN. Currently Futurae does not perform any validation on the quality of the supplied PIN. The app is assumed to ensure that the PIN meets the security standards as defined by the customer app logic and requirements (for example: PIN “1111” or “1234” is not allowed).

FuturaeSDK.getClient().enrollAndSetupSDKPin(
  //qrcode raw value
  scannedCode,
  //sdkpin set by the user
  sdkPin,
  //callbacks
  object : Callback<Unit> {

    override fun onSuccess(result: Unit) {
      //the account was enrolled and the SDK is unlocked
    }
    
    override fun onError(throwable: Throwable) {
      //handle enrollment failure
    }
  }) 

Logout (Unenroll)

To remove an account from this SDK (ie unenroll this user device), call the protected method logout():

//first, make sure the SDK is unlocked, then proceed

FuturaeSDK.getClient().logout(userId, new FuturaeCallback() {
  @Override
  public void success() {
    //handle logout success (eg. refresh accounts list)
  }

  @Override
  public void failure(Throwable throwable) {
    //handle logout failure
  }
});

Typically this should happen either when the user removes the account manually from the app, or when a user has been logged out remotely by the server. In the former case, calling the logout() method is enough, as it notifies the server of the logout and deletes the account from the SDK too. In the latter case, the server will send a FCM notification to the app, and the default handler of the notification will delete the account from the SDK as well. In this case, the notification handler will also send a local broadcast to the app (see INTENT_ACCOUNT_UNENROLL_MESSAGE above, so that the app can also perform any further action required (e.g. refresh the list of active accounts in an account view).

The intent contains the Futurae user_id, as well as the device_id, as an extra:

String userId = intent.getStringExtra(NotificationUtils.PARAM_USER_ID);
String deviceId = intent.getStringExtra(NotificationUtils.PARAM_DEVICE_ID);

To manually delete an account from the local database, which is needed for instance if you handle the FCM notifications without using FTRFcmMessagingService (see the Push notifications section) and an unenroll push notification is received, call the deleteAccount() method:

FuturaeSDK.getClient().deleteAccount(userId)

SDK biometrics configuration

The Futurae SDK allows the user to configure the device biometrics as a convenient way to verify the user presence and unlock the SDK. Once biometrics verification is enabled, it will become the first choice to perform the user presence verification.

The SDK may be unlocked using biometrics, given that the following conditions are met:

  • The SDK is configured with LockConfigurationType.BIOMETRICS_OR_DEVICE_CREDENTIALS, LockConfigurationType.SDK_PIN_WITH_BIOMETRICS_OPTIONAL or LockConfigurationType.BIOMETRICS_ONLY (in this last case, biometrics verification is mandatory as it is the only method available to unlock the SDK).
  • If the SDK is configured with LockConfigurationType.SDK_PIN_WITH_BIOMETRICS_OPTIONAL, then biometrics verification must be activated at the SDK level. To do so, the function activateBiometrics must be called. Not that only for this lock configuration type the app needs to activate biometrics verification at the SDK level. For all the other lock configuration types, biometrics verification will automatically be used to unlock the SDK, as long the user has biometrics configured as a lock mechanism to unlock the device.
  • The SDK biometric keys are valid. If the SDK configuration setInvalidatedByBiometricChange is set as true, in order for the SDK keys to be valid the following conditions must be verified:
    • No new biometrics were configured. If the user configures a new biometric entry in the device settings, the SDK biometrics will become invalid.
    • At least one of the biometrics remain configured since the last time that the SDK was initiatilized or the SDK biometrics were activated.
  • The user has at least one biometric verification option configured in the device settings.

Activate SDK biometrics verification

To activate the SDK biometrics verification the app needs to call the protected function activateBiometrics(), after verifying the user presence to unlock the SDK.

The activateBiometrics method is only available for the SDK_PIN_WITH_BIOMETRICS_OPTIONAL lock configuration type. If called right after enrolling the first account and setting up the SDK PIN with the method enrollAndSetupSDKPin, and before the unlockDuration expires, the app may call this function without having to unlock the SDK. This is particularly useful for apps that want to enforce biometrics as a user presence verification method.

The following example may be used for instance when the user enables biometrics verification in the app settings:

//first, make sure the SDK is unlocked with SDK PIN verification, then proceed
FuturaeSDK.getClient().activateBiometrics(

  //Activity required for the biometric authentication.
  requireActivity(),

  //Title used for the authentication prompt.
  "Unlock SDK",

  //Subtitle used for the authentication prompt.
  "Activate biometrics",

  //Description used for the authentication prompt.
  "Authenticate to enable biometric authentication",

  //Text for the “cancel” button of the Biometrics prompt.
  "cancel",

  //Callback to receive the result or error of this operation.
  object : Callback<Unit> {
    override fun onSuccess(result: Unit) {
      showAlert("SDK Unlock", "Biometric auth activated")
      //The SDK biometrics are enabled.
    }

    override fun onError(throwable: Throwable) {
      showErrorAlert("SDK Unlock", throwable)
      //Handle biometric activation failure.
    }

  }
)

Deactivate SDK biometrics verification

If the user wishes to deactivate biometrics verification, the app may use the protected deactivateBiometrics() function to revoke biometric authentication as an option to unlock the SDK.

Being a protected function, deactivateBiometrics may only be called after verifying the user presence to unlock the SDK.

//first, make sure the SDK is unlocked with SDK PIN verification, then proceed
FuturaeSDK.getClient().deactivateBiometrics(
  
  //callback to receive the result or error of this operation.
  object : Callback<Unit> {

    override fun onSuccess(result: Unit) {
      //handle successful biometrics deactivation
    }

    override fun onError(throwable: Throwable) {
      //handle failed biometrics deactivation
    }

})

Check if the SDK biometrics are valid

Specifically when the SDK is configured with setInvalidatedByBiometricChange(true), if new biometric credentials are configured in the device or in case that the user removes all the configured biometrics credentials, the SDK biometric verification will be automatically revoked and the user will have to explicitly activate it again using activateBiometrics as described above.

To check if the device biometric credentials have changed, the app may call the haveBiometricsChanged() method:

if (FuturaeSDK.getClient().haveBiometricsChanged()){
  // the device biometrics have changed, to reactivate call activateBiometrics()
}

Change SDK PIN

When the SDK LockConfigurationType is SDK_PIN_WITH_BIOMETRICS_OPTIONAL, the SDK PIN configured upon the first enrollment, may be updated with the protected function changeSDKPin() as shown next:

//first, make sure the SDK is unlocked with SDK PIN verification, then proceed
FuturaeSDK.getClient().changeSDKPin(it, object : Callback<Unit> {
  override fun onSuccess(result: Unit) {
    //handle successful SDK PIN change
  }

  override fun onError(throwable: Throwable) {
    //handle failed SDK PIN change
  }
})

Account status

To get a list of all enrolled accounts in this SDK, call the getAccounts() method:

List<FTAccount> accounts = FuturaeSDK.getClient().getAccounts();

In order to get a specific FTAccount, call the functions getFTAccountByUserId() or getAccountByUserIdAndDeviceId():


//get the FTAccount for the provided userId
FTAccount account = FuturaeSDK.getClient().getFTAccountByUserId(userId);

//get the FTAccount for the provided userId and deviceId
FTAccount account = FuturaeSDK.getClient().getAccountByUserIdAndDeviceId(userId, deviceId);

To fetch the status and pending authentication Authentication session information for these accounts, you can use the following method (where userIds is a list of the corresponding user IDs):

FuturaeSDK.getClient().getAccountsStatus(userIds, new FuturaeResultCallback<AccountsStatus>() {
  @Override
  public void success(AccountsStatus accountsStatus) {
    // Handle the pending sessions
  }

  @Override
  public void failure(Throwable throwable) {
    // Handle the error
  }
});

Authenticate user

One-Touch

When a One-Touch (aka Approve) session starts, the server will send a push notification to the app, where the user should approve or reject the authentication session. The notification is received and handled by the SDK, which in turn will send a local broadcast (see INTENT_APPROVE_AUTH_MESSAGE above), so that the app can perform any required actions. For example, the app might want to display a prompt to the user so that they can approve or reject the session.

The intent contains an object that describes the authentication session as an extra. This object contains the user ID and the session ID, which are required for sending the authentication outcome to the server:

ApproveSession authSession = intent.getParcelableExtra(NotificationUtils.PARAM_APPROVE_SESSION);
String userId = authSession.getUserId();
String sessionId = authSession.getSessionId();

Once the outcome of the authentication has been decided by the app, it should be sent to the server for the authentication session to complete.

Approve authentication

To approve the authentication session, when no extra_info is supplied in Authenticate with One-Touch, use the approveAuth() method. This is a protected method so the SDK must be first unlocked according to the configured SDK lockConfigurationType.

The following example demonstrates how to approve an authentication session when the SDK is unlocked by verifying user presence using biometrics:

FuturaeSDK.getClient().unlockWithBiometrics( //use the approriate unlock function
  requireActivity(),
  "Unlock SDK",
  "Authenticate with biometrics",
  "Authentication is required to unlock SDK operations",
  "cancel",
  object : Callback<Unit> {
    override fun onSuccess(result: Unit) {
      FuturaeSDK.approveAuth(
        //Futurae account's user id which the authentication was created for
        userId
        
        //session identifier returned by the Futurae backend Auth API
        sessionId

        //Callback to handle the success or failure of the approve operation
        object : Callback<Unit> {

          override fun onSuccess(result: Unit) {
            //handle session successful approved
          }

          override fun onError(throwable: Throwable) {
            //handle session approve failure
            showErrorAlert("Failed to approve session", throwable)
          }
        })
    }
    override fun onError(throwable: Throwable) {
      showErrorAlert("SDK Unlock failure", throwable)
    }
  }
)
Reject authentication

The user might choose to reject the authentication session. Additionally, in case the session has not been initiated by the user, they might also choose to report a fraudulent authentication attempt back to the server. In this case, and when no extra_info is supplied in Authenticate with One-Touch, use the following example to unlock the SDK, as this is a protected function, and reject an authentication with the rejectAuth() method:

FuturaeSDK.getClient().unlockWithSDKPin( //use the approriate unlock function
  sdkPin,
  object : Callback<Unit> {
    override fun onSuccess(result: Unit) {
      FuturaeSDK.rejectAuth(
        //Futurae account's user id which the authentication was created for
        userId
        
        //session identifier returned by the Futurae backend Auth API
        sessionId

        //boolean flag to choose whether to report a fraudulent authentication attempt
        reportFraud

        //Callback to handle the success or failure of the reject operation
        object : Callback<Unit> {

          override fun onSuccess(result: Unit) {
            //handle session successful rejected
          }

          override fun onError(throwable: Throwable) {
            //handle session reject failure
            showErrorAlert("Failed to reject session", throwable)
          }
        })
    }
    override fun onError(throwable: Throwable) {
      showErrorAlert("SDK Unlock failure", throwable)
    }
  }
)

Online QR code

The online QR Code authentication factor consists in using the authenticator app to scan a QR Code provided by the server.

To complete the authentication, provide the content of the online QR Code scanned by the user to the protected function approveAuth(), according to the following example:

FuturaeSDK.getClient().unlockWithSDKPin( //use the approriate unlock function
  sdkPin,
  object : Callback<Unit> {
    override fun onSuccess(result: Unit) {
      FuturaeSDK.approveAuth(
        //raw value parsed from the scanned QR code.
        qrCode

        //Callback to handle the success or failure of the approve operation
        object : Callback<Unit> {

          override fun onSuccess(result: Unit) {
            //handle session successful approved
          }

          override fun onError(throwable: Throwable) {
            //handle session approve failure
            showErrorAlert("Failed to approve session", throwable)
          }
        })
    }
    override fun onError(throwable: Throwable) {
      showErrorAlert("SDK Unlock failure", throwable)
    }
  }
)

Offline QR code

Offline QR code allows the user to authenticate by scanning a QR code, without the need of an internet connection on the authenticator device.

To authenticate with the offline QR code Factor, scan the QR code provided by the server and display the relevant information to the user. If the user approves the authentication or transaction request, the app may use the following methods to generate the 6-digit verification code that the user needs to enter in the browser.

In the case of the SDK_PIN_WITH_BIOMETRICS_OPTIONAL lock configuration type, since the SDK PIN is being validated server side, the app needs to act differently on functions that can take place while offline. Specifically, computeVerificationCodeFromQRCode is a protected function that requires prior unlocking of the SDK. However, for the case that the app is offline the SDK offers the following equivalent function that are not protected but require either passing the SDK PIN as argument or if biometrics are activated then the computeVerificationCodeFromQRCodeWithBiometrics method shall be used.

The method computeVerificationCodeFromQrcode() generates the verification code by passing the SDK PIN as argument:

//provide the sdkPin inserted by the user to generate the OTP
result = FuturaeSDK.getClient().computeVerificationCodeFromQrcode(qrCode,sdkPin)
//display the $result (6 digit offline code) to the user

To generate the verification code when the biometrics verification is activated, call the computeVerificationCodeFromQrCodeWithBiometrics() method, which will initiate the user biometrics verification prompt, and then compute the code based on the biometrics result:

FuturaeSDK.getClient().computeVerificationCodeFromQrCodeWithBiometrics(
  qrCode,
  requireActivity(),
  "Unlock SDK",
  "Authenticate with biometrics",
  "Authentication is required to unlock SDK operations",
  "cancel",
  object : Callback<Unit> {
    override fun onSuccess(result: String) {
      //display the $result (verification code) to the user
    }
    override fun onError(throwable: Throwable) {
      showErrorAlert("Failed to generate offline authentication code", throwable)
    }
  }
)

Finally, the verification code can be computed by passing only the QR code data to the computeVerificationCodeFromQrcode method. Nevertheless, user presence has to be verified before that:

//first, make sure the SDK is unlocked, then proceed
FuturaeSDK.getClient().computeVerificationCodeFromQrcode(qrCodeString);

IMPORTANT: In case the backend API Authenticate with Offline QR code (or Authenticate Transaction with Offline QR code) is invoked with supplying the extra_info input parameter (for example, when contextual information for logins, or transaction details for transaction authentication), which includes information that must be displayed to the user before they can approve/reject the request, then you can retrieve this information from the QR code itself, as shown below:

ApproveInfo[] extraInformation = FuturaeClient.getExtraInfoFromOfflineQrcode(qrCode);

Authentication session information

For a given authentication session, either identified via a session ID (e.g. received by a push notification) or a session Token (e.g. received by a QRCode scan), you can ask the Futurae backend for more information about the session, using the protected methods sessionInfoById() or sessionInfoByToken() respectively:

//first, make sure the SDK is unlocked, then proceed

// if you have a session ID
FuturaeSDK.getClient().sessionInfoById(
  userId, 
  sessionId, 
  object : FuturaeResultCallback<SessionInfo> {
    override fun success(sessionInfo: SessionInfo) {
      // Handle the session
    }

    override fun failure(t: Throwable) {
      // Handle the error
    }
  }
);

// if you have a session Token
FuturaeSDK.getClient().sessionInfoByToken(
  userId, 
  sessionToken, 
  object : FuturaeResultCallback<SessionInfo?> {
    override fun success(sessionInfo: SessionInfo?) {
      // Handle the session
    }

    override fun failure(t: Throwable) {
      // Handle the error
    }
  }
);

If there is extra information to be displayed to the user (supplied when calling Authenticate User or Authenticate Transaction in the backend API), for example when confirming a transaction, this will be indicated with a list of key-value pairs in the extra_info part of the response.

In order to query the server for the authentication session information, you need the user ID and the session ID or session token. You can use the following helper methods to obtain these from either a URI or a QR Code:

public class FuturaeClient {
  public static String getUserIdFromQrcode(String qrCode);
  public static String getSessionTokenFromQrcode(String qrCode);
  public static String getUserIdFromUri(String uri);
  public static String getSessionTokenFromUri(String uri);
}
Authentication with extra information

In case it exists, you can retrieve the extra information that the user needs to review while authenticating by calling the getApproveInfo() method on the SessionInfo object:

public ApproveInfo[] getApproveInfo();

Each ApproveInfo object is a key-value pair that describes a single piece of information; call the following methods to retrieve the key and value of the object respectively.

public String getKey();
public String getValue();

IMPORTANT: In case the authentication contains extra_info, it is mandatory that the information is fetched from the server, displayed to the user, and included in the authentication response in order for it to be included in the response signature. Otherwise, the server will reject the authentication response. Use the following methods to send an authentication response including the authentication information:

class FuturaeClient {
  public void approveAuth(String qrCode, final FuturaeCallback callback, ApproveInfo[] extraInfo);
  public void approveAuth(String userId, String sessionId, final FuturaeCallback callback, ApproveInfo[] extraInfo);
  public void rejectAuth(String userId, String sessionId, boolean reportFraud, final FuturaeCallback callback, ApproveInfo[] extraInfo);
}

TOTP

TOTP authentication can be used for offline authentication, as there is no requirement for an internet connection in the app.

The protected method nextTopt() is used to get the current TOTP, when the SDK LockConfigurationType is other than SDK_PIN_WITH_BIOMETRICS_OPTIONAL:

//first, make sure the SDK is unlocked, then proceed

CurrentTotp totp = FuturaeSDK.getClient().nextTotp(userId);

// The TOTP that the user should use to authenticate
String passcode = totp.getPasscode();

// The remaining seconds of validity of this TOTP
int remainingSeconds = totp.getRemainingSecs();

As seen in this example, the nextTotp() method returns an object that contains the TOTP itself, but also the remaining seconds that this TOTP will be still valid for. After this time, a new TOTP must be obtained by the SDK.

When the SDK LockConfigurationType is SDK_PIN_WITH_BIOMETRICS_OPTIONAL, and the user has no biometrics verification enabled, the user presence is then validated using the SDK PIN. In that case the nexTotp method may be used to authenticate when the user has no internet connection, by adding the the SDK PIN argument:

CurrentTotp totp = FuturaeSDK.getClient().nextTotp(userId, sdkPin);

When the SDK is configured with SDK_PIN_WITH_BIOMETRICS_OPTIONAL, if biometrics verification is activated, the TOTP may be generated using the nextTotpWithBiometrics() method:

FuturaeSDK.getClient().nextTotpWithBiometrics(
  userId,
  requireActivity(),
  "Unlock SDK",
  "Authenticate with biometrics",
  "Authentication is required to unlock SDK operations",
  "cancel",
  object : Callback<Unit> {
    override fun onSuccess(result: CurrentTotp) {
      //display the $result (TOTP) to the user
    }
    override fun onError(throwable: Throwable) {
      showErrorAlert("Failed to generate offline authentication code", throwable)
    }
  }
)

URI schemes

The SDK is able to handle URI scheme calls, which can be used to either enroll or authenticate users. Once your activity has been set up to handle the URI scheme call intents, get the intent data in the onCreate() method of your activity, which contains the URI that should be passed in the SDK, using the protected method handleUri():

//first, make sure the SDK is unlocked, then proceed

FuturaeSDK.getClient().handleUri(
  uriString, 
  object : FuturaeCallback() {
    override fun success() {
      //handle success
    }

    override fun failure(throwable: Throwable) {
      //handle failure
    }
});

IMPORTANT: In case you perform authentication with a URI scheme call (using the mobile_auth_uri value which is returned by the Futurae backend when calling Authenticate User or Authenticate Transaction), and this authentication includes extra information to be displayed to the user, you must retrieve this information from the server and include it in the authentication response. See section Authentication session information for details on how to do that.

Automatic Account Recovery

Automatic account recovery (aka account migration) allows the user to migrate the Futurae account(s) currently enrolled in an existing Futurae Android SDK installation to a different device, or to the same one after erasing and reinstalling an app. This mechanism migrates the accounts using data which were backed up by the Android OS when the previous app installation had enrolled account(s). Hence, it enables the user to recover their accounts on a new app installation automatically.

On the fresh app installation, the SDK is able to identify if account migration is possible and return the number of accounts which can be migrated. In order to do so, invoke the method checkAccountMigrationPossible():

FuturaeSDK.getClient().checkAccountMigrationPossible(new FuturaeResultCallback<Integer>() {
  @Override
  public void success(Integer numAccounts) {
    // Account migration is possible - unsigned integer indicates the number of accounts to be migrated to this device
  }

  @Override
  public void failure(Throwable throwable) {
    // Checking for account migration eligibility failed. Handle the error
  }
});

To execute account migration invoke the executeAccountMigration() method. The migrated accounts (i.e., Futurae user ids) will be returned, if successful.

FuturaeSDK.getClient().executeAccountMigration(
  new FuturaeResultCallback<AccountsMigrationResource.MigrationAccount[]>() {
    @Override
    public void success(AccountsMigrationResource.MigrationAccount[] result) {
      // Account migration finished successfully - array of all Futurae user_ids which were migrated successfully
    }

    @Override
    public void failure(Throwable throwable) {
      // Account migration failed. Handle the error
    }
  }
);

IMPORTANT: In order for account migration to be feasible on the new device, the following are required:

  • The migration data of the SDK in the previous app installation must have been previously backed up, so that the SDK in the fresh app installation can retrieve them. See Enabling SDK Backup and Restore for instructions on how to achieve this.
  • The SDK in the new app installation must have no other accounts currently or previously enrolled.

You may catch exceptions thrown by the checkAccountMigrationPossible() and executeAccountMigration() methods by catching com.futurae.sdk.AccountsMigrationException or for specific cases the following exceptions that inherit from it:

  • com.futurae.sdk.AccountsMigrationAccountsExistException: Indicates that account migration is not possible due to at least one account currently existing on the device.
  • com.futurae.sdk.AccountsMigrationAccountsPreviouslyEnrolledException: Indicates that account migration is not possible due to at least one account having previously been enrolled on the device.
  • com.futurae.sdk.AccountMigrationNoMigrationInfoException: Indicates that account migration is not possible due to no account migration data availability.
  • com.futurae.sdk.AccountsMigrationUnexpectedException: Indicates that a an unexpected error occurred during checking or executing account migration.

Enabling SDK Backup and Restore

In order for the Futurae Android SDK to be able to include the necessary data in the Android backup, as well as retrieve them, you need to create a BackupAgent class (extending android.app.backup.BackupAgent) and declare it in your AndroidManifest.xml file as follows:

<application
  android:allowBackup="true"
  android:backupAgent="<PATH_TO_BACKUPAGENT_CLASS>">

In your BackupAgent class make sure to override onBackup(...) and onRestore(...) like in the following example. If you want to backup and restore only Futurae related data, invoke the onBackupAccounts() inside onBackup(...) and onRestoreAccounts() inside onRestore(...). On the other hand, if you have your own data to backup and restore, then during onRestore(...) iterate the keys inside BackupDataInput and pass the entity data to the SDK’s onRestoreAccountsData(...):

@Override
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) {
  try {
    // App-specific backup logic, if you have any, goes here...

    com.futurae.sdk.BackupAgent.onBackupAccounts(this, oldState, data, newState);
  } catch (IOException e) {
    // Handle exception
  }
}

@Override
public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) {
  try {
    // If your app backs up data that you want to restore in your own code by iterating data keys/values,
    // then all the data your app code doesn't handle must be passed to com.futurae.sdk.BackupAgent.onRestoreAccountsData(Context,BackupDataInput).
    // For a detailed implementation example, check our public demo app.
    //
    // Otherwise let the SDK handle the migration entirely by calling com.futurae.sdk.BackupAgent.onRestoreAccounts().
    com.futurae.sdk.BackupAgent.onRestoreAccounts(this, data, appVersionCode, newState);
  } catch (IOException e) {
    // Handle exception
  }
}

The signatures of the two methods are the following:

public static void onBackupAccounts(Context context, ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) throws IOException
public static void onRestoreAccounts(Context context, BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) throws IOException

Public key pinning

Public key pinning is by default enabled in Futurae Android SDK so that it only accepts a specific list of public keys when connecting to the Futurae backend over TLS. No further configuration is necessary.

Reset SDK data

The SDK provides a convenient method to clear all SDK internal data, including accounts, cryptographic keys and secrets, as well as the lock configuration. After successfully calling the reset() function, all the enrolled accounts will be removed, and they will need to enrolled again if needed.

The SDK may be reset in the following situations:

  • To change the SDK lockConfigurationType, the SDK needs to be reset first and then initialized again with the new configuration.
  • When the SDK setInvalidatedByBiometricChange is true, the SDK may need to be reset and initialized again, depending on the lockConfigurationType (see User presence verification section).
  • If there are unexpected issues, you may try to reset and re-launch the SDK.

SDK protected functions

Some of the SDK functions are protected with an extra security layer, therefore they can only be called by the app when the SDK is in an unlocked status. In order to unlock the SDK, user presence must be verified depending on the SDK lockConfigurationType (see User presence verification section).

SDK protected functions

SDK unlock functions

The SDK provides unlock functions that when called, user presence is verified, and if successful the SDK is unlocked for the configured unlockDuration. The unlock functions which may be used, depend on the configured lockConfigurationType (see User presence verification section).

SDK unlock functions