Mobile SDK: iOS

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

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 iOS FuturaeKit SDK release history and changes here.

Migrate from SDK v1.x.x

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

  1. Get the SDK v2.x.x from from our 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.
  • Add the NSFaceIDUsageDescription key to your Info.plist file. Please refer to the section Configuration and Initialization.
  • The clear SDK data method clearDataFromDB was deprecated. Instead the reset method should be called
  1. Then launch the SDK using the lock configuration type as NONE. After launching the SDK with lock configuration type 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 that supports user presence verification, after launching the SDK using LockConfigurationTypeNone you can perform an SDK configuration switch. Alternatively 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 Xcode for your development. You can install FuturaeKit into your project using:

SwiftPM

As of Xcode 12.0 (and Swift Tools 5.3) it is possible to integrate FuturaeKit directly within Xcode.

To add FuturaeKit follow the usual way of adding a package dependency:

File -> Swift Packages -> Add Package Dependency

In the window that pops up simply enter: https://github.com/Futurae-Technologies/ios-sdk.git as the package repository URL.

The FuturaeKit framework should automatically be added to your project: you’re good to go!

To make sure that your application runs on a device, add the following “Run Script Phase” command to your App’s target build phases, to force deep sign the frameworks with your own signing identity:

find "${CODESIGNING_FOLDER_PATH}" -name '*.framework' -print0 | while read -d $'\0' framework
do
    codesign --force --deep --sign "${EXPANDED_CODE_SIGN_IDENTITY}" --preserve-metadata=identifier,entitlements --timestamp=none "${framework}"
done

Carthage

Carthage is a lightweight dependency manager for Swift and Objective-C. It leverages CocoaTouch modules and is less invasive than CocoaPods.

To install with Carthage, follow the instruction on Carthage. We support integration using Carthage binary frameworks. You can add FuturaeKit by adding the following line to your Cartfile

binary "https://raw.githubusercontent.com/Futurae-Technologies/ios-sdk/master/CarthageJson/FuturaeKit.json"

Then run carthage bootstrap (or carthage update is you’re updating your SDKs).

On your application targets' “Build Phases” settings tab, click the “+” icon and choose “New Run Script Phase”. Create a Run Script in which you specify your shell (e.g., /bin/sh), add the following contents to the script area below the shell:

/usr/local/bin/carthage copy-frameworks

Add the paths to the framerworks you want to use under “Input Files”, e.g.:

$(SRCROOT)/Carthage/Build/iOS/FuturaeKit.framework

CocoaPods

It is assumed that your application has CocoaPods integrated. Otherwise please follow the official CocoaPods guide to integrate CocoaPods dependency manager to your app (How to install CocoaPods, How to use cocoapods).

The snippet below is a minimal Podfile to integrate FuturaeKit to your project. The notes are provided below.

platform :ios, '11.0' #1
source 'https://github.com/CocoaPods/Specs.git' #2

target 'FuturaeKitCocoapods' do
  use_frameworks! #3
  pod 'FuturaeKit' #4
end

Notes:

  1. As per CocoaPods requirements, one may specify iOS minimal supported version. The Podfile needs to comply with a minimal version constraint of every library. The FuturaeKit supports iOS versions 11.0 and above. Reference: Cocoapods syntax guide.
  2. CocoaPods uses a CDN to deliver specs. It means that the source directive is not strictly necessary. However, there is no policy as to when and how often the CDN is updated. Because of that, the newest FuturaeKit package might not be available under CDN on the same day that the release is published, or even several days after. To get timely updates, please include the source directive. Otherwise the immediate availability of latest FuturaeKit package updates is not guaranteed.
  3. FuturaeKit is distributed as a compiled framework. Depending on your project needs, you may or not use the use_frameworks directive. This setting should not affect FuturaeKit’s linking to your project.
  4. pod directive instructs CocoaPods to add FuturaeKit to your project. It’s possible to freeze a specific FuturaeKit version if you prefer. Please refer to the official guide on how to specify a pod version.

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.

Add SDK to project

You can include the FuturaeKit SDK by adding the FuturaeKit.framework manually to your targets Embedded Binaries (in the General tab). Afterwards, drag the FuturaeKit.framework into the Frameworks group of your project.

ios_sdk_add_to_project

Configuration and initialization

The NSFaceIDUsageDescription key is required for apps that uses Face ID APIs, that being the case this key needs to be declared in your Info.plist file, in order to describe the reasons for the app to use Face ID.

FuturaeKit SDK is a dynamic framework, so you should use the following import statement:

#import <FuturaeKit/FuturaeKit.h>

Initialize the SDK

In the Project Navigator, open the source file of your application delegate and add the above import statement at the top of the file. Then, in the didFinishLaunching or didFinishLaunchingWithOptions method of your app delegate, create the SDK configuration instance FTRConfig, and provide it as argument to the launchWithConfig method:

#import <FuturaeKit/FuturaeKit.h>

// ...
FTRConfig *ftrConfig = [FTRConfig configWithSdkId:@"{FuturaeSdkId}" 
                                           sdkKey:@"{FuturaeSdkKey}" 
                                          baseUrl:@"https://api.futurae.com:443"
                                lockConfiguration:[[LockConfiguration alloc]
                                        initWithType:LockConfigurationTypeBiometricsOnly
                                      unlockDuration:5
                       invalidatedByBiometricsChange:YES]];

//launch SDK with configuration
[FTRClient launchWithConfig:ftrConfig  success:^{
            //success
        } failure:^(NSError * _Nonnull error) {
            // error
        }];

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.

The SDK initWithType method arguments are described in detail in the User presence verification section.

Once the SDK is initialized, the FTRClient instance may be accessed through the following getter:

[FTRClient sharedClient]

Build your app

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

Keychain configuration

Keychain sharing and access groups

By default the SDK stores its keychain items in the app’s default access group. This should be sufficient in most cases. Nevertheless, if your app is sharing access to keychain items with other apps then from a security point of view, the keychain items which belong to the Futurae SDK should not be shared, and thus they should be stored in an access group that is only accessible by the app that hosts the SDK. If the app’s default access group is shared with other apps, then another one should be used instead.

For this reason, the SDK provides the ability to specify the keychain access group to which the SDK-owned keychain items should be stored. The specified access group must not be shared with other apps.

#import <FuturaeKit/FuturaeKit.h>

// ...
FTRKeychainConfig *keychainConfig = [FTRKeychainConfig configWithAccessGroup:@"{teamID}.com.example.appPrivateGroup"];
FTRConfig *ftrConfig = [FTRConfig configWithSdkId:@"{FuturaeSdkId}"
                                           sdkKey:@"{FuturaeSdkKey}"
                                          baseUrl:@"https://api.futurae.com:443"
                                         keychain:keychainConfig
                                lockConfiguration:[[LockConfiguration alloc]
                                        initWithType:LockConfigurationTypeBiometricsOnly
                                      unlockDuration:5
                       invalidatedByBiometricsChange:YES]];

//launch SDK with configuration

When a keychain access group is specified, like in the example above, the SDK will automatically migrate all its keychain items to the specified access group, in the case that they are previously stored in a different access group. This ensures that if an already existing app, which was not originally configured to specify an access group when initializing the SDK), changes the behavior to specify an access group in a future release, then existing installations will have the Futurae SDK keys migrated to the specified access group after the relevant app update.

Note that if the SDK cannot store its items in the specified access group (for example, if the app doesn’t have the entitlement to do so) then it will raise an NSException.

Keychain items accessibility

By default the SDK stores its keychain items using the kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly accessibility value.

You can choose a different accessibility value, depending on the use case and requirements of your application, using one of the available FTRKeychainItemAccessibility values (which map directly to the respective iOS accessibility values), when initializing the SDK. For example:

#import <FuturaeKit/FuturaeKit.h>

// ...
FTRKeychainConfig *keychainConfig = [FTRKeychainConfig configWithCryptoItemsAccessibility:FTRKeychainItemAccessibilityWhenUnlockedThisDeviceOnly];
FTRConfig *ftrConfig = [FTRConfig configWithSdkId:@"{FuturaeSdkId}"
                                           sdkKey:@"{FuturaeSdkKey}"
                                          baseUrl:@"https://api.futurae.com:443"
                                         keychain:keychainConfig];
                                lockConfiguration:[[LockConfiguration alloc]
                                        initWithType:LockConfigurationTypeBiometricsOnly
                                      unlockDuration:5
                       invalidatedByBiometricsChange:YES]];
//launch SDK with configuration

Refer to the content of the FTRKeychainConfig.h file for further information on the available options for FTRKeychainItemAccessibility.

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 iOS provides the following features and functionality:

Callbacks

For operations related to locking/unlocking that can either succeed or fail, the user needs to pass in a callback implementation of the following type:

typedef void (^FTRLockHandler)(NSError * _Nullable error);

If the error is null it means the operation was successful.

Push notifications

To enable push notifications add the following call in the didFinishLaunching or didFinishLaunchingWithOptions method of your app delegate:

// push notifications
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_9_x_Max) { // iOS 10+
  UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
  center.delegate = self;
  [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge)
                              completionHandler:^(BOOL granted, NSError * _Nullable error) {
                                  // NOTE: To be completed
                              }];
} else { // iOS 8+ without UserNotifications Framework
  UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound) categories:nil];
  [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
}

[[UIApplication sharedApplication] registerForRemoteNotifications];

To send the push notification token, add the following call in the didRegisterForRemoteNotificationsWithDeviceToken method of your app delegate:

- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {

    [[FTRClient sharedClient] registerPushToken:deviceToken];
}

To handle the Futurae push notifications, implement the FTRNotificationDelegate and add the handleNotification call in the respective method of your app delegate (didReceiveRemoteNotification:fetchCompletionHandler: or pushRegistry:didReceiveIncomingPushWithPayload:):

- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type
{
    [[FTRClient sharedClient] handleNotification:payload delegate:self];
}

IMPORTANT:The handleNotification method requires the SDK to be unlocked in case that the notification payload includes extra_info. To check if the payload has extra info you can check the boolean value for the key has_extra in the payload dictionary: payload[@"has_extra"]

Encrypted Push Notifications

The Futurae Authentication platform provides a mechanism to encrypt the extra information that is provided in the context of a Push authentication or Transaction signing session. In case the session contains extra_info, the encrypted data can be retrieved as a string from the userInfo dictionary of the push notification under the key encrypted_info_enc. This string can be passed to the SDK protected function decryptExtraInfo:userId:error: which will decrypt it and return an array of dictionaries:

    NSError *error;
    NSString *encryptedExtraInfo = userInfo[@"extra_info_enc"];
    NSString *userId = userInfo[@"user_id"];
    NSArray<NSDictionary *> *extraInfo = [FTRClient.sharedClient decryptExtraInfo:encryptedExtraInfo userId:userId error:&error];

The SDK function decryptExtraInfo:userId:error: is a protected function so the SDK has to be unlocked before decrypting the extra information content.

In order to call the SDK method decryptExtraInfo:userId:error: within an app extension such as UNNotificationServiceExtension, the App Groups and Keychain Access Group needs to be configured as described in the section below.

Configuring App Group and Keychain Access Group

In order to call SDK methods from app extensions (such as UNNotificationServiceExtension) or to share the same SDK between different apps you need to utilize the App Groups and Keychain Access Group capabilities.

When initializing the SDK in the main app or the app extension, the app group and keychain app group identifier may be passed as following:

FTRConfig *ftrConfig = [FTRConfig configWithSdkId:@"{FuturaeSdkId}"
                                           sdkKey:@"{FuturaeSdkKey}"
                                          baseUrl:@"{FuturaeBaseUrl}"
                                         keychain: [FTRKeychainConfig configWithAccessGroup:@"{KeychainAccessGroupId}"]
                                lockConfiguration:[[LockConfiguration alloc]
                                        initWithType:LockConfigurationTypeBiometricsOnly
                                      unlockDuration:5
                       invalidatedByBiometricsChange:YES]
                                         appGroup: @"{AppGroupId}"
];
//launch SDK with configuration
[FTRClient launchWithConfig:ftrConfig  success:^{
            //success
        } failure:^(NSError * _Nonnull error) {
            // error
        }];

Migrating to using App Group and Keychain Access Group for the SDK

SDK instances created without setting the appGroup and keychain parameter in the launch configuration, will need to explicitly call the protected method updateSDKConfig(withAppGroup:keychainConfig:callback:) in order to update the SDK configuration with the appGroup and Keychain details.

[FTRClient.sharedClient updateSDKConfigWithAppGroup: @"{AppGroupId}"
                                           keychainConfig:[FTRKeychainConfig configWithAccessGroup:@"{KeychainAccessGroupId}"]
                                                 callback:^(NSError * _Nullable error) {
        if(!error){
            // If update was successful you can set a bool value in the user defaults and check for this value in subsequent launches of the SDK
            // and if set to true you can include the new values for app group and keychain parameter in the launch configuration.
            [NSUserDefaults.standardUserDefaults setBool:YES forKey:@"app_groups_migrated"];
        }
    }];

Check if SDK data exists for a specified configuration

In order to check if there is data present for a specific SDK configuration, the checkDataExistsForAppGroup:keychainConfig:lockConfiguration: method can be called before launching the SDK. This method accepts as argument the App Group id, a keychain configuration object with the Keychain Access Group id and the SDK lockConfiguration object, and returns true if SDK is able to find data matching the provided configuration, otherwise it returns false.


//appGroup and keychainConfig can be nil to check if there is SDK data without App Group and Keychain Access Group configuration
BOOL sdkDataExists = [FTRClient checkDataExistsForAppGroup: @"{AppGroupId}"
                                            keychainConfig:[FTRKeychainConfig configWithAccessGroup:@"{KeychainAccessGroupId}"]
                                         lockConfiguration:[[LockConfiguration alloc] initWithType:LockConfigurationTypeBiometricsOnly unlockDuration:5 invalidatedByBiometricsChange:YES]];

When switching between configurations in the SDK, such as updating the configuration to use App Group, switching lock configuration types, or changing the hosting app keychain access group, the information about the recently used configuration might be lost on the app side in subsequent launches of the SDK. In that case, by calling the method checkDataExistsForAppGroup:keychainConfig:lockConfiguration: before launching, the app can determine which configuration has existing data and then proceed launching with that configuration if the method returns true.

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. It leverages the device lock mechanisms, such as biometrics (e.g. Touch ID or Face ID), passcode or an SDK PIN (also known as Custom App PIN) set by the user upon the first enrollment, to validate user presence when certain actions are carried out by the Futurae SDK, thus providing an extra layer of security to these operations.

The SDK initWithType method 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.

type - This parameter sets the user presence verification lock configuration type between the following options:

  • LockConfigurationTypeNone - 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.
  • LockConfigurationTypeBiometricsOnly - This lock configuration type allows the end user to only unlock the SDK through strong biometric authentication.
  • LockConfigurationTypeBiometricsOrPasscode - The SDK can be unlocked by authenticating either using the device biometrics or the passcode.
  • LockConfigurationTypeSDKPinWithBiometricsOptional - 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.

unlockDuration - 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 throw an error. If the unlock duration is not set, then the SDK will assume a default value of 60 seconds.

invalidatedByBiometricsChange - If set to YES, 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:

  • LockConfigurationTypeSDKPinWithBiometricsOptional - The app can either re-activate the 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 lock configuration type is LockConfigurationTypeBiometricsOnly or LockConfigurationTypeSDKPinWithBiometricsOptional.

When the SDK lock configuration type is LockConfigurationTypeSDKPinWithBiometricsOptional, a server-side verification of the SDK PIN takes place, therefore network connectivity is required.

FTRClient *client = [FTRClient sharedClient];
[client unlockWithBiometrics:^(FTRError * _Nullable error) {
            if(error){
                // user verification failed
            } else {
                // unlock verification success
            }
    } promptReason:@Unlock SDK];

Verify user presence with biometrics or device passcode

if the SDK lock configuration type is set as LockConfigurationTypeBiometricsOrPasscode, 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 passcode.

The method unlockWithBiometricsPasscode 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 passcode.

FTRClient *client = [FTRClient sharedClient];
[client unlockWithBiometricsPasscode:^(FTRError * _Nullable error) {
            if(error){
                // user verification failed
            } else {
                // unlock verification success
            }
    } promptReason:@Unlock SDK];

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 LockConfigurationTypeSDKPinWithBiometricsOptional 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.

FTRClient *client = [FTRClient sharedClient];

//the app must implement a mechanism to ask the user to insert the sdkPIN
[client unlockWithSDKPin:sdkPIN callback:^(FTRError * _Nullable error) {
    if(error){
        // user verification failed
    } else {
        // unlock verification success
    }
}];
SDK PIN entry constraints

As the SDK PIN is verified by the Futurae backend, the constraints described below are imposed on the server side.

  1. The SDK PIN validation is limited to 5 consecutive failed attempts, and the at the 5th consecutive failed attempt the SDK will enter a permanent locked state.

  2. The failed SDK PIN entry attempts are consecutive. A user may enter a wrong pin 4 times without consequences. If the correct SDK PIN is entered during the 5th attempt, the failed attempts counter is reset to 0.

  3. After a successful SDK PIN validation, the SDK PIN failed attempts counter is reset to 0.

  4. The SDK does not enforce specific SDK PIN patterns or restrictions, since the PIN policies can be enforced by the host app.

SDK locked due to consecutive SDK PIN failed attempts

When the SDK is locked due to failed SDK PIN attempts:

  • The SDK is permanently locked and cannot be used again.
  • The user device in the Futurae backend is archived and cannot be used to authenticate the user anymore.
  • Once locked due to failed SDK PIN attempts, the SDK will need to be reset.
  • The user will need to re-enroll all previously enrolled accounts.

The following SDK errors related to SDK PIN can be caught and handled by the hosting app:

  • FTRApiErrorPinNotNeeded: When the SDK PIN is provided but not required.
  • FTRApiErrorMissingPin: Indicates that the SDK PIN is missing or empty.
  • FTRBackendErrorCodeUnauthorizedPinWrongAttempt1: If the user enters an incorrect SDK PIN for the 1st time, this code will be triggered. It also means that there are 4 more attempts left to enter the correct SDK PIN.
  • FTRBackendErrorCodeUnauthorizedPinWrongAttempt2: When the user enters an incorrect SDK PIN for the 2nd time. It also informs that there are 3 more attempts left to enter the correct SDK PIN.
  • FTRBackendErrorCodeUnauthorizedPinWrongAttempt3: When the user enters an incorrect SDK PIN for the 3rd time. It also informs that there are 2 more attempts left to enter the correct SDK PIN.
  • FTRBackendErrorCodeUnauthorizedPinWrongAttempt4: When the user enters an incorrect SDK PIN for the 4th time. It also informs that there is 1 more attempt left to enter the correct SDK PIN.
  • FTRApiErrorIncorrectPinArchivedDevice: When the SDK PIN validation fails for the 5th consecutive time, thus the SDK is permanently locked.

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.

FTRClient *client = [FTRClient sharedClient];
[client 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.

FTRClient *client = [FTRClient sharedClient];
if ([client 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:

FTRClient *client = [FTRClient sharedClient];
NSArray *unlockMethods = [client getActiveUnlockMethods];

//Mapping of UnlockMethodType values
typedef NS_ENUM(NSInteger, UnlockMethodType) {
    UnlockMethodTypeBiometric = 1,
    UnlockMethodTypeBiometricsOrPasscode = 2,
    UnlockMethodTypeSDKPin = 3,
    UnlockMethodTypeNone = 4,
};

Switch SDK configuration

The SDK provides a way to switch to a different SDK configuration post initialization via the following methods:

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)
  • Approve or reject an authentication session not attached to a specific user (usernameless)

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:

NSString *QRCodeString = ...
switch ([FTRClient QRCodeTypeFromQRCode:QRCodeString]) {
    case FTRQRCodeTypeEnrollment:
        // handle Enrollment
        break;
    case FTRQRCodeTypeOnlineAuth:
        // handle Online QR code authentication
        break;
    case FTRQRCodeTypeOfflineAuth:
        // handle Offline QR code authentication
        break;
    case FTRQRCodeTypeInvalid:
        // handle invalid QR code
        break;
    case FTRQRCodeTypeUsernameless:
        // handle usernameless QR code
        break;
}

Enroll

To enroll this SDK as a device for a Futurae User, there are two options. Enrollment via an activation QR code and enrollment via an activation shortcode.

Enroll with QR code

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:

// first, make sure the SDK is unlocked, then proceed
[[FTRClient sharedClient] enroll:code callback:^(NSError *error) {

}];

You can either call directly the above method or use a QR-Code Reader UIViewController to scan a code:

FTRQRCodeViewController *qrcodeVC = [[FTRQRCodeViewController alloc] init];
qrcodeVC.delegate = self;
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:qrcodeVC];
[self presentViewController:navigationController animated:YES completion:nil];

If a QR-Code is successfully scanned then the following delegate method with be called, with the scanned code:

- (void)reader:(FTRQRCodeViewController * _Nullable)reader didScanResult:(NSString *_Nullable)result
{
  ...
}

Please make sure to call the enroll function, inside the delegate method to complete the user enrollment:

// first, make sure the SDK is unlocked, then proceed
[[FTRClient sharedClient] enroll:result callback:^(NSError *error) {

}];

Enroll with activation shortcode

To enroll with an activation shortcode, call the the protected method enrollWithActivationShortCode:callback: method using a valid activation code:

// first, make sure the SDK is unlocked, then proceed
[FTRClient.sharedClient enrollWithActivationShortCode:code callback:^(NSError *error) {
    
}];

Enroll and setup the SDK PIN

When the SDK lock configuration type is LockConfigurationTypeSDKPinWithBiometricsOptional, the user must set the SDK PIN upon the first enrollment, therefore the activation of the first account is perfomed by calling the SDK methods enrollAndSetupSDKPin:code:callback: or enrollAndSetupSDKPin:activationShortCode:callback: 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).

[FTRClient.sharedClient enrollAndSetupSDKPin:sdkPIN code:QRCodeResult callback:^(NSError * _Nullable error) {

}];

Logout (Unenroll)

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

// first, make sure the SDK is unlocked, then proceed
[[FTRClient sharedClient] logoutUser:userId callback:^(NSError *error) {

}];

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 logoutuser method is enough, as it notifies the server of the logout and deletes the account from the SDK too.

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 the 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 LockConfigurationTypeBiometricsOrPasscode, LockConfigurationTypeSDKPinWithBiometricsOptional or LockConfigurationTypeBiometricsOnly (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 LockConfigurationTypeSDKPinWithBiometricsOptional, then biometrics verification must be enabled at the SDK level. To do so, the function activateBiometrics must be called. 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 invalidatedByBiometricsChange 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 method activateBiometrics, after verifying the user presence to unlock the SDK.

The activateBiometrics method is only available for the LockConfigurationTypeSDKPinWithBiometricsOptional 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
FTRClient *client = [FTRClient sharedClient];
NSError *error = [client activateBiometrics];
if (error) {
    // SDK biometrics activation failed
} else
{
    // SDK biometrics activated
};

Deactivate SDK biometrics verification

If the user wishes to deactivate biometrics verification, the app may use the protected deactivateBiometrics method 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
FTRClient *client = [FTRClient sharedClient];
NSError *error = [client deactivateBiometrics];
if (error) {
    // SDK biometrics deactivation failed
} else
{
    // SDK biometrics deactivated
};

Check if the SDK biometrics are valid

Specifically when the SDK lock configuration type is LockConfigurationTypeSDKPinWithBiometricsOptional and the invalidatedByBiometricsChange settings is configured as YES, 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 or reset the SDK if the SDK is configured with LockConfigurationTypeBiometrics or LockConfigurationTypeBiometricsOrPasscode.

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

FTRClient *client = [FTRClient sharedClient];
BOOL haveBiometricsChanged = [client haveBiometricsChanged];
if (haveBiometricsChanged) {
    // SDK biometrics have changed
} else
{
    // SDK biometrics have not changed
};

Change SDK PIN

When the SDK lock configuration type is LockConfigurationTypeSDKPinWithBiometricsOptional, 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
[[FTRClient sharedClient] changeSDKPin:sdkPIN callback:^(FTRError * _Nullable error) {
    if(error){
        // success
    } else {
        // failure
    }
}];

Account status

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

NSArray *accounts = [[FTRClient sharedClient] getAccounts];

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

[[FTRClient sharedClient] getAccountsStatus:accounts
                                    success:^(id _Nullable data) {
                                        // Handle the pending sessions
                                    }
                                    failure:^(FTRError * _Nullable error) {
                                        // Handle the error
                                    }];

Account History

Protected function to get a list of all authentications for an enrolled account in the SDK, call the getAccountHistory method:

[FTRClient.sharedClient getAccountHistory:account success:^(id responseObject) {
        //account history
    }
    failure:^(NSError * _Nullable error) {
        //error
    }];

Authenticate user

To authenticate (or reject) a user session, depending on the authentication factor, you can use the following methods:

One-Touch

With One-Touch (aka Approve), the server will send a push notification to the app, where the user should approve or reject the authentication session.

Get the user ID and session ID from the push notification handler. Once the outcome of the authentication has been decided (e.g., approved/rejected by the user), it should be sent to the server for the authentication session to complete, using one of the methods described in the subsections below.

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 lock configuration type.

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

FTRClient *client = [FTRClient sharedClient];
 [client unlockWithBiometrics:^(FTRError * _Nullable error) {
            if(error){
                // user verification failed
            } else {
                // unlock verification success
                [client approveAuthWithUserId:userId 
                                    sessionId:sessionId 
                                     callback:^(FTRError * _Nullable error) {
                    if(error){
                        // authentication failed
                    } else {
                        // authentication success
                    }
                }];
            }
    } promptReason:@Unlock SDK];

To approve a user authentication when extraInfo field has a non-null value (refer to authentication session information):

// first, make sure the SDK is unlocked, then proceed
[[FTRClient sharedClient] approveAuthWithUserId:userId
                                      sessionId:sessionId
                                      extraInfo:extraInfo
                                       callback:^(FTRError * _Nullable error) {

}];
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 rejectAuthWithUserId method:

FTRClient *client = [FTRClient sharedClient];
 [client unlockWithBiometrics:^(FTRError * _Nullable error) {
            if(error){
                // user verification failed
            } else {
                // unlock verification success
                [client rejectAuthWithUserId:userId 
                                   sessionId:sessionId 
                                     isFraud:@(NO) 
                                    callback:^(FTRError * _Nullable error) {
                    //handle callback result
                }];
            }
    } promptReason:@Unlock SDK];

To reject a user authentication when extraInfo field has a non-null value (refer to authentication session information), and optionally define it as fraud:

// first, make sure the SDK is unlocked, then proceed
[[FTRClient sharedClient] rejectAuthWithUserId:userId sessionId:sessionId
                                                        isFraud:@(NO)
                                                      extraInfo:extraInfo
                                                       callback:^(FTRError * _Nullable error) {

}];
Approve with Multi-Numbered Challenge

If Multi-Numbered Challenge is enabled for your Futurae Service, push notifications sent to the app will contain an array of numbers under the key multi_numbered_challenge which can be found within the authenticationInfo dictionary provided by the method approveAuthenticationReceived(_:) of the FTRNotificationDelegate protocol.

// for example AppDelegate.h

- (void)approveAuthenticationReceived:(nonnull NSDictionary *)authenticationInfo {
  
  // ...
  NSArray<NSNumber *> *numbersChallenge = authenticationInfo[@"multi_numbered_challenge"];
}

You can also retrieve the multi_numbered_challenge values from the session info (refer to authentication session information):

It is up to the client application to present user with a choice of numbers. User’s choice has to be passed back to the SDK’s approveAuth(withUserId:sessionId:multiNumberChoice:callback:) method.

[[FTRClient sharedClient] approveAuthWithUserId:userId
                                      sessionId:sessionId
                              multiNumberChoice:multiNumberChoice
                                       callback:^(FTRError * _Nullable error) {

}];

Backend installation receives the correct choice in the response to the authentication call. The correct choice is unknown (not sent) to the SDK. To let user know of the correct choice, it has to be displayed on the application where transaction was initialized.

To approve a user authentication with multi-numbered challange when extraInfo field has a non-null value (refer to authentication session information):

// first, make sure the SDK is unlocked, then proceed
[[FTRClient sharedClient] approveAuthWithUserId:userId
                                      sessionId:sessionId
                                      extraInfo:extraInfo
                              multiNumberChoice:multiNumberChoice
                                       callback:^(FTRError * _Nullable error) {

}];

Online QR code

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

In the following example the user is verified by validating the SDK PIN, then the content of the online QR code scanned by the user, is passed to the protected method approveAuthWithQrCode:

FTRClient *client = [FTRClient sharedClient];
[client unlockWithSDKPin:sdkPIN callback:^(FTRError * _Nullable error) {
            if(error){
                // user verification failed
            } else {
                // unlock verification success
                [client approveAuthWithQrCode:qrCodeScanResult 
                                     callback:^(FTRError * _Nullable error) {
                    //handle callback result
                }];
            }
    } promptReason:@Unlock SDK];

In case the backend API Authenticate with QR code (or Authenticate Transaction with 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 must retrieve this information from the Futurae backend and include it in the authentication response. See section authentication session information for more information, and then use the following method:

FTRClient *client = [FTRClient sharedClient];
 [client unlockWithBiometrics:^(FTRError * _Nullable error) {
            if(error){
                // user verification failed
            } else {
                // unlock verification success
                [client approveAuthWithQrCode:qrCodeScanResult 
                                    extraInfo:extraInfo 
                                     callback:^(FTRError * _Nullable error) {
                    //handle callback result
                }];
            }
    } promptReason:@Unlock SDK];

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 LockConfigurationTypeSDKPinWithBiometricsOptional 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:

NSError *error = nil;
NSString *verificationCode = [FTRClient.sharedClient computeVerificationCodeFromQRCode:QRCodeString 
                                                                                SDKPin:SDKPin
                                                                                 error:&error];
if (error == nil) {
  // Verification code generated successfully.
}

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:

FTRClient *client = [FTRClient sharedClient];
[client computeVerificationCodeFromQRCodeWithBiometrics:qrCodeScanResult 
                                               callback:^(FTRError * _Nullable err, NSString * _Nullable code) {
    //display the code to the user
}promptReason:@Unlock SDK];

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
NSError *error = nil;
NSString *verificationCode = [FTRClient.sharedClient computeVerificationCodeFromQRCode:QRCodeString
                                                                                 error:&error];
if (error == nil) {
  // Verification code generated successfully.
}

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:

NSArray<FTRExtraInfo *> *extraInformation = [FTRClient.sharedClient extraInfoFromOfflineQRCode:QRCodeString];

Usernameless QR Code

To approve a usernameless QR code session, first scan the QR Code provided by the server, then fetch the session info via the QR Code’s token and finally approve with an enrolled user’s id using the protected methods approveAuthWithUsernamelessQrCode:userId:callback: or approveAuthWithUsernamelessQrCode:userId:extraInfo:callback::

[FTRClient.sharedClient approveAuthWithUsernamelessQrCode:QRCodeResult userId: userId callback:^(NSError * _Nullable error) {
        
}];

To approve a usernameless QR code session when extraInfo field has a non-null value (refer to authentication session information):

[[FTRClient sharedClient] approveAuthWithUsernamelessQrCode:QRCodeResult
                                                     userId:userId
                                                  extraInfo:extraInfo
                                                   callback:^(FTRError * _Nullable error) {

}];

To reject a usernameless QR code session use the protected methods rejectAuthWithUsernamelessQrCode:userId:isFraud:callback: or rejectAuthWithUsernamelessQrCode:userId:isFraud:extraInfo:callback:.

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 method getSessionInfo:

// if you have a session ID
FTRClient *client = [FTRClient sharedClient];
[client getSessionInfo:userId
             sessionId:sessionId
               success:^(id  _Nullable data) {
    //handle session data        
}
               failure:^(NSError * _Nullable error) {
    //failed to get session info
}];

// if you have a session Token
FTRClient *client = [FTRClient sharedClient];
[client getSessionInfo:userId
          sessionToken:sessionToken
               success:^(id  _Nullable data) {
    //handle session data        
}
               failure:^(NSError * _Nullable error) {
    //failed to get session info
}];

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 of the FTRUtils class to obtain these identifiers from either a URI or a QR Code:

+ (NSString * _Nullable)userIdFromQrcode:(NSString *)qrCode;
+ (NSString * _Nullable)sessionTokenFromQrcode:(NSString *)qrCode;
+ (NSString * _Nullable)userIdFromUri:(NSString *)uri;
+ (NSString * _Nullable)sessionTokenFromUri:(NSString *)uri;

TOTP

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

The protected method nextTotpForUser is used to get the current TOTP, when the SDK lock configuration type is other than LockConfigurationTypeSDKPinWithBiometricsOptional:

//first, make sure the SDK is unlocked, then proceed
NSError *error;
FTRTotp *result = [[FTRClient sharedClient] nextTotpForUser:user_id 
                                                      error:&error];

// The TOTP that the user should use to authenticate
NSString *totp = result.totp;

// The remaining seconds of validity of this TOTP
NSString *remaining_secs = result.remaining_secs;

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 app.

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

NSError *error;
FTRTotp *result = [[FTRClient sharedClient] nextTotpForUser:user_id
                                                     SDKPin:SDKPin
                                                      error:&error];

When the SDK is configured with LockConfigurationTypeSDKPinWithBiometricsOptional, if biometrics verification is activated, the TOTP may be generated using the nextTotpForUser method:

FTRClient *client = [FTRClient sharedClient];
[client nextTotpForUserWithBiometrics:userId
                             callback:^(FTRError * _Nullable err, FTRTotp * _Nullable totp) {
    //display the totp to the user
}promptReason:@Unlock SDK];

Synchronous Authentication Token

Protected function that creates an OTP based authentication token that can be used with the Authenticate with Synchronous Auth endpoint for synchronous authentication. To get a sychronous authentication token for an enrolled user, use the synchronousAuthTokenForUser method:

[FTRClient.sharedClient synchronousAuthTokenForUser:account.user_id callback:^(NSError * _Nullable error, NSString * _Nullable token) {
        if (error) {
            // handle error
            return;
        }
        
        // handle token
}];

As a result of the above method, the mobile SDK will return a synchronous authentication token that can be used to authenticate the user. The token is returned to the mobile app, that has to submit it to the customer backend, which in turn needs to provide the token to the Authenticate with Synchronous Auth Auth API endpoint, in order to authenticate the user.

Users already enrolled will also be able to perform synchronous authentication. After migrating to an SDK version that supports this factor, once the app is launched, the SDK will add the sync factor to the device’s capabilities, provided that the device has stable internet connection, otherwise if it fails to update the sync capability the SDK will try again upon each launch until a successful update.

URI schemes

The SDK is able to handle URI scheme calls, which can be used to either enroll or authenticate users. To handle the Futurae URI scheme calls, implement the FTROpenURLDelegate and add the openURL call in the openURL:sourceApplication:annotation: method of your app delegate:

//first, make sure the SDK is unlocked, then proceed
[[FTRClient sharedClient] openURL:url options:options delegate:self];

IMPORTANT: In case you perform authentication using 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 iOS SDK installation to:

  1. the same or a different device when restoring the device via an iCloud or encrypted iTunes backup, or
  2. the same device after erasing and reinstalling the SDK-enabled mobile app.

This 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 checkMigratableAccountsSuccess:failure::

[FTRClient.sharedClient checkMigratableAccountsSuccess:^(FTRMigrationCheckData *data) {
        if (data.pinProtected || LockConfiguration.get.type == LockConfigurationTypeSDKPinWithBiometricsOptional) {
            //Proceed with executeAccountMigrationWithSDKPin:success:failure:
        } else {
            //Proceed with executeAccountMigrationSuccess:failure:
        }

    } failure:^(NSError * _Nonnull error) {
        // Checking for account migration eligibility failed
    }];

To execute account migration invoke the executeAccountMigrationSuccess or executeAccountMigrationWithSDKPin:success:failure: methods, depending on the result of the check operation above and your active SDK configuration’s LockConfigurationType. The migrated accounts (i.e., Futurae user ids) will be returned, if successful.

[FTRClient.sharedClient executeAccountMigrationSuccess:^(NSArray<FTRAccount *> * _Nonnull accountsMigrated) {
    // Account migration finished successfully - array of all Futurae user_ids which were migrated successfully
} failure:^(NSError * _Nonnull error) {
    // Account migration failed
}];

The method executeAccountMigrationWithSDKPin should be called in either of the below scenarios:

  • If the accounts to be recovered were originally enrolled on an SDK configured with SDK PIN (or later switched to an SDK PIN configuration), then the user must be asked to insert the SDK PIN configured on the previous SDK in order to confirm the account migration process, and the inserted SDK PIN is provided as argument to the executeAccountMigrationWithSDKPin method.
  • If the accounts to be recovered were not protected by an SDK PIN and the current lock configuration type is LockConfigurationTypeSDKPinWithBiometricsOptional the provided SDK PIN to the executeAccountMigrationWithSDKPin method will be used as the new SDK PIN for unlocking the SDK.

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

  • If restoring a device from a backup, the migration data of the SDK in previous app installation must have been included in the backup of the device from which the current device is restored. Additionally, they iCloud Keychain must have been enabled in the previous device and must be enabled in the new device, as well.
  • The SDK in the new app installation must have no other accounts currently or previously enrolled.

There is a dedicated enum to distinguish errors that might occur during checking or executing account migration:

typedef NS_CLOSED_ENUM(NSUInteger, FTRAccountMigrationError) {
    FTRAccountMigrationErrorNoMigrationInfo = 900,
    FTRAccountMigrationErrorAccountsExistError = 901,
    FTRAccountMigrationErrorAccountPreviouslyEnrolledError = 902,
    FTRAccountMigrationErrorPinRequired = 903
};

If code in NSError object is different than the one above it means that a server error occurred. You can access the error’s userInfo dictionary for a more readable description of the error.

Adaptive

Using state-of-the-art technology, Adaptive reduces fraud risk by analyzing numerous device-inherit and environmental signals simultaneously to build a user-specific secure context.

Permissions

There is a way to ask for permissions on your own (to avoid displaying all at once, one after another, and in order to sufficiently explain to the user why these permissions are needed and for what purpose the data is used), however you need to remember about postponing the enabling of the adaptive mechanism when doing so, since first you need to ask for all required permissions (code example below) and only then enable adaptive.

To inform the SDK which adaptive permissions are currently granted you need to provide a delegate which conforms to the FTRAdaptiveSDKDelegate delegate. You set this delegate when you enable the adaptive mechanism.

lazy var locationManager = CLLocationManager()
lazy var bluetoothManager = CBCentralManager()
lazy var serviceBrowser = NetServiceBrowser()

func requestForLocationPermission() {
    locationManager.requestWhenInUseAuthorization()
}

func requestForBluetoothPermission() {
    _ = bluetoothManager
}

func requestForNetworkPermission() {
    serviceBrowser.searchForServices(ofType: "_http._tcp.", inDomain: "") // or any other operation that requires network usages
}

To be able to use the adaptive mechanism in the Futurae SDK you have to configure the following first (important note: An exception will be thrown if these are not set up.)

1. Set up Bluetooth

For iOS 13+, Add Privacy - Bluetooth Always Usage Description key to your Info.plist.

<key>NSBluetoothAlwaysUsageDescription</key>
<string>{{App}} requires bluetooth access to scan for nearby devices.</string>

For iOS 6.0–13.0, Add Privacy - Bluetooth Peripheral Usage Description key to your Info.plist.

<key>NSBluetoothPeripheralUsageDescription</key>
<string>{{App}} requires bluetooth access to scan for nearby devices.</string>
2. Set up Local Network
2.1 Add WiFi capability

In your Xcode project, select the Capabilities tab and choose Access WiFi Information from the list.

2.2 Edit Info.plist

For iOS 14.0+, Add Privacy - Local Network Usage Description key to your Info.plist.

<key>NSLocalNetworkUsageDescription</key>
<string>{{App}} requires network access to scan your local network for devices and services</string>

Add Bonjour services key to your Info.plist with a list of services:

<key>NSBonjourServices</key>
<array>
  <string>_smb._tcp.</string>
  <string>_privet._tcp.</string>
  <string>_device-info._tcp.</string>
  <string>_sftp-ssh._tcp.</string>
  <string>_airplay._tcp.</string>
  <string>_scanner._tcp.</string>
  <string>_mediaremotetv._tcp.</string>
  <string>_rdlink._tcp.</string>
  <string>_rfb._tcp.</string>
  <string>_uscan._tcp.</string>
  <string>_companion-link._tcp.</string>
  <string>_apple-mobdev2._tcp.</string>
  <string>_b._dns-sd._udp.</string>
  <string>_afpovertcp._tcp.</string>
  <string>_nfs._tcp.</string>
  <string>_webdav._tcp.</string>
  <string>_ftp._tcp.</string>
  <string>_ssh._tcp.</string>
  <string>_eppc._tcp.</string>
  <string>_http._tcp.</string>
  <string>_telnet._tcp.</string>
  <string>_printer._tcp.</string>
  <string>_ipp._tcp.</string>
    <string>_pdl-datastream._tcp.</string>
  <string>_riousbprint._tcp.</string>
  <string>_daap._tcp.</string>
  <string>_dpap._tcp.</string>
  <string>_ichat._tcp.</string>
  <string>_presence._tcp.</string>
  <string>_ica-networking._tcp.</string>
  <string>_airport._tcp.</string>
  <string>_xserveraid._tcp.</string>
  <string>_distcc._tcp.</string>
  <string>_apple-sasl._tcp.</string>
  <string>_workstation._tcp.</string>
  <string>_servermgr._tcp.</string>
  <string>_raop._tcp.</string>
  <string>_xcs2p._tcp.</string>
</array>
3. Set up Location

For iOS 11.0+, Add Privacy - Location When In Use Usage Description key to your Info.plist.

<key>NSLocationWhenInUseUsageDescription</key>
<string>{{App}} requires access to your location</string>

Usage

In order to enable the adaptive mechanism you need to import the Adaptive SDK framework to your app. You can find the Adaptive SDK repository here.

After launching the SDK (see Initialize the SDK section), you can enable adaptive via the following:

[FTRClient.sharedClient enableAdaptiveWithDelegate:delegate];

Here delegate is an object that conforms to the FTRAdaptiveSDKDelegate protocol.

You can disable adaptive via the following:

[FTRClient.sharedClient disableAdaptive];

As long as Adaptive SDK is enabled, context collections will occur regularly. The data collected depends on the runtime permissions which were granted to the app as well as the device’s quick-settings. E.g. location data will not be available if the user’s device has the location setting turned off. Refer to the Permissions section for more.

User Risk Radar

User Risk Radar is an Adaptive solution that provides an effective mechanism to reduce the risk of fraudulent authentication or transaction signing attempts. For further details on how this feature works, refer to the User Risk Radar guide.

To use this feature, follow the instructions described on the sections Permissions and Usage. Additionally, contact support@futurae.com to enable User Risk Radar for your Futurae Service.

Adaptive Account Recovery

Adaptive Account Recovery provides the same functionality as Automatic Account Recovery but with an additional security layer that validates if the user is on a trusted context, before allowing the accounts to be recovered. For more details about this feature refer to the Adaptive Account Recovery guide.

Whenever a user attempts an adaptive account recovery in a new app installation (or reinstallation), the Futurae SDK performs a fresh scan to gather the available contextual data of the new device, and subsequently compares it with the data which has been previously observed for the specific user. If the new device is in a so-called trusted context, then the account migration request is deemed safe and hereby allowed. If the context is not known, the request is denied and the account recovery process is not allowed to happen automatically. Instead the user should be prompted to contact the Customer’s support desk, in order to perform an assisted activation of the new device.

To use this feature, follow the instructions described on the sections Permissions and Usage. Additionally, contact support@futurae.com to enable Adaptive Account Recovery for your Futurae Service.

Adaptive Account Recovery is executed using the same methods checkAccountMigrationPossibleSuccess and executeAccountMigrationSuccess as Automatic Account Recovery.

Error handling

If Adaptive is enabled calling executeAccountMigrationSuccess may also return one of the following Adaptive error codes:

  • 40300 when the accounts migration feature is disabled in the backend
  • 40302 when the adaptive mechanism does not allow a migration to be completed successfully (only if the adaptive mechanism is enabled)

Public Key Pinning

The Futurae mobile SDK employs a public key pinning (SSL pinning) mechanism to protect secure traffic from the MITM attacks.

The SDK’s public key pinning mechanism is always enabled and no further configurations are required on the app side. The pinCerts parameter of the FTRConfig constructor is deprecated and it’s not required anymore. If provided, the pinCerts configuration will be ignored.

In order to activate the public key pinning mechanism of the Futurae iOS SDK so that it only accepts a specific list of public keys when connecting to the Futurae backend over TLS, you need to perform the following steps:

  1. Find the keys to be pinned, in a self-signed certificate format, here.
  2. Copy these certificates into the Resources folder of your app, as is the case for the example demo app in the repo above. The Futurae iOS SDK will pick them up from there and load them to enable the pinning mechanism for these specific keys.
  3. Make sure to initialize FTRConfig with pinCerts = true. Important! Unless FTRConfig is explicitly initialized with pinCerts = true, this configuration defaults to false.

Device jailbreak detection

The SDK offers a mechanism to detect if the device on which the app is installed, is jailbroken. To run the test, call jailbreakStatus method of the FTRClient:

JailbreakStatus *status = FTRClient.sharedClient.jailbreakStatus;

The returned object has a flag status.jailbroken that reports whether a device is jailbroken (true) or not (false). The property status.message provides a description concerning the jailbroken mechanism detected in the device, if any.

status.jailbroken // Boolean
status.message // String

Integrity verdict

The SDK offers a mechanism to validate that the application is installed from a valid channel of acquisition, i.e. Apple’s App Store. To run the integrity check, call the appAttestation(_:production:callback:) method of the FTRClient.

[FTRClient.sharedClient appAttestation:"{appId}"
                            production: YES/NO
                              callback:^(NSError*  _Nullable error) {
    // failed if error is not null
}];

If error is not null, then the app integrity check has failed, otherwise the app integrity check has successfully passed.

For more information about Apple’s App Attest service visit the developer guide.

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 be enrolled again if needed.

The SDK may be reset in the following situations:

SDK client delegates

The SDK provides two primary delegate protocols that host applications can implement to receive notifications about various events, such as URL openings and push notification actions. These delegates are crucial for handling authentication, activation, QR code scanning, and user unenrollment actions within your application.

FTROpenURLDelegate

The FTROpenURLDelegate protocol informs the delegate about URL openings related to authentication and activation.

Methods:

FTRNotificationDelegate

The FTRNotificationDelegate protocol allows the delegate to be informed about events received via push notifications.

Methods:

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 lock configuration type (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