Skip to main content

Face authentication

About this documentation

This documentation only describes how to configure the SDK for our face authentication feature. If you want to learn about the feature and the full set of implementation requirements, see the main feature documentation:


Configure the SDK

To use face authentication, you need to incorporate the FaceTec SDKs.

The FaceTec SDK is available for download from our repository. The repository is gated, therefore you require login credentials to access it.

  1. Request your Nexus repository login credentials from us by creating a support ticket in the Signicat Dashboard.
  2. Navigate to our repository, then enter your Nexus repository login credentials.
  3. Download the FaceTec SDK.
  4. Drag and drop the FaceTecSDK.xcframework file into your project.
    Note

    Ensure that you select the Copy items if needed checkbox.

  5. In your project settings, navigate to Target > General. Set the FaceTec framework to Embed & Sign.
  6. Open the Info.plist file, then add the new entry Privacy - Camera Usage Description.

How to implement face authentication

Overview

To implement face authentication, you must typically use the following flow:

  1. Start the process for either Add or update or for Authentication. You will then receive a serverSideFaceInit object.
  2. Initialise the FaceTec SDK with the authorisations received from the serverSideFaceInit object.
  3. The end-user performs the FaceScan, which provides a sessionResult.
  4. Provide the FaceScanData object with the sessionResult, then finish the Add or update or Authentication.

For further details specific to the operation, see the relevant sub-chapters.

Activation

Activation will be supported in a future release. This means that currently, you must:

  1. Activate with PIN and/or biometrics.
  2. Use the Add or update operation to add face authentication.

AddOrUpdate

Start call

For an example of startAddOrUpdate, click to expand the collapsible section:

Click to expand
import FaceTecSDK

class ViewController: UIViewController {

var encapController = EncapController.shared

private func startAddOrUpdateOfAuthMethod(clientData: String?) {

let startParam = StartAddOrUpdateParameter(selectedAuthMethod: .serverSideFace(faceScanData: nil))
self.encapController.startAddOrUpdate(startAddOrUpdateParameter: startParam, onCompletion: { result in
switch result {
case .success(let successResult):
if let serverSideFaceInit = successResult.serverSideFaceInit {
self.initializeFacetecSDK(serverSideFaceInitResult: serverSideFaceInit)
}
case .failure(let errorResult):
self.handleError(errorResult, in: .stateStartAddOrUpdate)
}
})
}
}


extension ViewController: FaceTecFaceScanProcessorDelegate {

func initializeFacetecSDK(serverSideFaceInitResult: EncapSwiftAPI.ServerSideFaceInitResult) {

if let deviceKeyIdentifier = serverSideFaceInitResult.deviceKeyIdentifier, let encryptionKey = serverSideFaceInitResult.encryptionKey, let sessionToken = serverSideFaceInitResult.sessionToken, let productionKeyText = serverSideFaceInitResult.productionKeyText {

FaceTec.sdk.initializeInProductionMode(productionKeyText: productionKeyText, deviceKeyIdentifier: deviceKeyIdentifier, faceScanEncryptionKey: encryptionKey, completion: { initializationSuccessful in
if(initializationSuccessful) {

let verificationVC = FaceTec.sdk.createSessionVC(faceScanProcessorDelegate: self, sessionToken: sessionToken)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.present(verificationVC, animated: true, completion: nil)
}
} else {
// Initialization of Facetec SDK failed
}
})
} else {
// Something missing
}
}

// MARK: FaceTec Delegate

func processSessionWhileFaceTecSDKWaits(sessionResult: FaceTecSessionResult, faceScanResultCallback: FaceTecFaceScanResultCallback) {

switch sessionResult.status {
case .sessionCompletedSuccessfully:

faceScanResultCallback.onFaceScanResultCancel()
let faceScanData = FaceScanData(faceScanBase64: sessionResult.faceScanBase64 ?? "", auditTrailImageBase64: sessionResult.auditTrailCompressedBase64?.first ?? "", lowQualityAuditTrailImageBase64: sessionResult.lowQualityAuditTrailCompressedBase64?.first ?? "")
self.handleFinishLogicForFacetec(faceScanData: faceScanData)
case .userCancelled:
faceScanResultCallback.onFaceScanResultCancel()
default:
faceScanResultCallback.onFaceScanResultCancel()
self.showAlert(title: "Error", message: errorHandler(facetecSessionResult: sessionResult))
}
}
}

Finish call

For an example of finishAddOrUpdate, click to expand the collapsible section:

Click to expand

private func handleFinishLogicForFacetec(faceScanData: FaceScanData?) {

let toAuthenticate: AuthMethod = .pin(value: "1111")
// You can also authenticate using other methods e.g.
// let toAuthenticate: AuthMethod = .faceID
// let toAuthenticate: AuthMethod = .strongTouchID(prompt: nil)
self.finishAddOrUpdateOfAuthMethod(withAuthMethod: .serverSideFace(faceScanData: faceScanData),toAuthenticate: toAuthenticate)
}

func finishAddOrUpdateOfAuthMethod(withAuthMethod toActivate: AuthMethod, toAuthenticate: AuthMethod) {
self.animate()

self.activeController.finishAddOrUpdate(authMethodToActivate: toActivate, authMethodToAuthenticate: toAuthenticate,onCompletion: { result in
self.stopAnimate()
switch result {
case .success(let finishAddOrUpdateResult):
// Done
case .failure(let errorResult):
// Handle error
}
})
}

Authentication

To be able to conduct a face authentication, you must start the process using the REST API.

To do this, start a new authentication, where the request has the authentication_method field defined with the value DEVICE_SERVER_SIDE_FACE.

Start call

For an example of startAuthentication, click to expand the collapsible section:

Click to expand
import FaceTecSDK

class ViewController: UIViewController {

var encapController = EncapController.shared

private func startAuthentication(clientData: String?) {

self.encapController.startAuthentication(clientOnly: false, onCompletion: { result in
switch result {
case .success(let successResult):
if let serverSideFaceInit = successResult.serverSideFaceInit {
self.initializeFacetecSDK(serverSideFaceInitResult: serverSideFaceInit)
}
case .failure(let errorResult):
// handle Error
}
})
}
}


extension ViewController: FaceTecFaceScanProcessorDelegate {

func initializeFacetecSDK(serverSideFaceInitResult: EncapSwiftAPI.ServerSideFaceInitResult) {

if let deviceKeyIdentifier = serverSideFaceInitResult.deviceKeyIdentifier, let encryptionKey = serverSideFaceInitResult.encryptionKey, let sessionToken = serverSideFaceInitResult.sessionToken, let productionKeyText = serverSideFaceInitResult.productionKeyText {

FaceTec.sdk.initializeInProductionMode(productionKeyText: productionKeyText, deviceKeyIdentifier: deviceKeyIdentifier, faceScanEncryptionKey: encryptionKey, completion: { initializationSuccessful in
if(initializationSuccessful) {
self.setCustomization()
let verificationVC = FaceTec.sdk.createSessionVC(faceScanProcessorDelegate: self, sessionToken: sessionToken)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.present(verificationVC, animated: true, completion: nil)
}
} else {
// Initialization of Facetec SDK failed
}
})
} else {
// Something missing
}
}

// MARK: FaceTec Delegate

func processSessionWhileFaceTecSDKWaits(sessionResult: FaceTecSessionResult, faceScanResultCallback: FaceTecFaceScanResultCallback) {

switch sessionResult.status {
case .sessionCompletedSuccessfully:

faceScanResultCallback.onFaceScanResultCancel()
let faceScanData = FaceScanData(faceScanBase64: sessionResult.faceScanBase64 ?? "", auditTrailImageBase64: sessionResult.auditTrailCompressedBase64?.first ?? "", lowQualityAuditTrailImageBase64: sessionResult.lowQualityAuditTrailCompressedBase64?.first ?? "")
self.handleFinishLogicForFacetec(faceScanData: faceScanData)
case .userCancelled:
faceScanResultCallback.onFaceScanResultCancel()
default:
faceScanResultCallback.onFaceScanResultCancel()
self.showAlert(title: "Error", message: errorHandler(facetecSessionResult: sessionResult))
}
}
}

Finish call

For an example of finishAuthentication, click to expand the collapsible section:

Click to expand

private func handleFinishLogicForFacetec(faceScanData: FaceScanData?) {

self.finishAuthentication(withAuthMethod: .serverSideFace(faceScanData: faceScanData))
}


func finishAuthentication(with authMethod: AuthMethod, tokenPurpose: TokenPurpose = .none) {

self.encapController.finishAuthentication(withAuthMethod: authMethod, tokenPurpose: tokenPurpose, onCompletion: { result in

switch result {
case .success(let finishAuthResult):
// Done
case .failure(let errorResult):
// handle Error
}
})
}

Error handling

Errors relating to FaceScan are propagated as follows:

  1. Using the FaceTec delegate in your class, you must have the function processSessionWhileFaceTecSDKWaits(sessionResult: FaceTecSessionResult, faceScanResultCallback: FaceTecFaceScanResultCallback).
  2. The callback of delegate of the process will be available in sessionResult (FaceTecSessionResult).
  3. You can check the status, which will indicate whether the session was either:
    • Completed successfully.
    • The cause of the failure.

Example: Code sample for error handling

Click to expand

func processSessionWhileFaceTecSDKWaits(sessionResult: FaceTecSessionResult, faceScanResultCallback: FaceTecFaceScanResultCallback) {
switch sessionResult.status {
case .sessionCompletedSuccessfully:
// Successfully
case .userCancelled:
faceScanResultCallback.onFaceScanResultCancel() // Dismiss FaceTec screen
default:
faceScanResultCallback.onFaceScanResultCancel() // Dismiss FaceTec screen
self.showAlert(title: "Error", message: errorHandler(facetecSessionResult: sessionResult))
}
}

private func errorHandler(facetecSessionResult: FaceTecSessionResult) -> String {

var subTitle = ""
switch facetecSessionResult.status {
case .sessionUnsuccessful:
subTitle = "The Facetec Session was not performed successfully and a FaceMap was not generated."
case .nonProductionModeKeyInvalid:
subTitle = "Your license is invalid or network connectivity issues occur during a session"
case .cameraPermissionDenied:
subTitle = "Camera Permission Denied"
case .contextSwitch:
subTitle = "Session was canceled due to the app being terminated, put to sleep, an OS notification, or the appwas placed in the background"
case .landscapeModeNotAllowed:
subTitle = "Session was canceled because device is in landscape mode"
case .reversePortraitNotAllowed:
subTitle = "Session was canceled because device is in reverse portrait mode"
case .timeout:
subTitle = "Session was canceled because the user was unable to complete a Facetec Session in the defaultallotted time"
case .lowMemory:
subTitle = "Session was canceled due to memory pressure"
case .nonProductionModeNetworkRequired:
subTitle = "Session was canceled because your App is not in production and requires a network connection"
case .gracePeriodExceeded:
subTitle = "Session was canceled because your License needs to be validated again"
case .encryptionKeyInvalid:
subTitle = "Session was canceled because the developer-configured encryption key was not valid"
case .missingGuidanceImages:
subTitle = "Session was canceled because not all guidance images were configured"
case .cameraInitializationIssue:
subTitle = "Session was canceled because Facetec was unable to start the camera on this device"
case .lockedOut:
subTitle = "Session was canceled because the user was in a locked out state"
case .unknownInternalError:
subTitle = "Session was canceled because of an unknown and unexpected error"
default:
subTitle = "\(facetecSessionResult.status.rawValue)"
}
return subTitle
}

Localisation

The FaceTecSDK includes language resource strings prefixed with FaceTec_. It supports the following languages:

  • Afrikaans (af)
  • Arabic (ar)
  • German (de)
  • Greek (el)
  • English (en)
  • Spanish (es)
  • French (fr)
  • Kazakh (kk)
  • Norwegian (nb)
  • Portuguese (pt-BR)
  • Russian (ru)

For further details, see the FaceTecSDK.zip file.

Branding and styling

What elements can be customised?

The FaceTec SDK allows you to customise various branding and styling elements, such as:

  • Interface
  • Colours
  • Fonts
  • Borders

To learn more about what you can customise, see the If you want to know more about what you can customise see the UX, Themes & Branding page in the FaceTec documentation.

How to customise the configuration

To make changes, you have to create a FaceTecCustomization object, where you define each field that you want to change.

Example: Facetec customisation configuration
let blueLeft = UIColor.init(red: 97/255, green: 210/255, blue: 250/255, alpha: 1)
let blueRight = UIColor.init(red: 28/255, green: 122, blue: 247/255, alpha: 1)
let gradientCgColor: [CGColor] = [blueLeft.cgColor, blueRight.cgColor]
let fontBody = UIFont.systemFont(ofSize: 16, weight: .regular)

let customization = FaceTecCustomization()
customization.overlayCustomization.brandingImage = UIImage(named: "brandLogo")
customization.frameCustomization.borderColor = blueLeft
let backgroundLayer = CAGradientLayer.init()
backgroundLayer.colors = gradientCgColor
backgroundLayer.locations = [0,1]
backgroundLayer.startPoint = CGPoint.init(x: 0, y: 0.5)
backgroundLayer.endPoint = CGPoint.init(x: 1, y: 0.5)
customization.feedbackCustomization.backgroundColor = backgroundLayer
customization.feedbackCustomization.textFont = fontBody
customization.ovalCustomization.strokeColor = blueLeft
customization.ovalCustomization.progressColor1 = blueLeft
customization.ovalCustomization.progressColor2 = blueRight

customization.guidanceCustomization.foregroundColor = blueLeft
customization.guidanceCustomization.readyScreenTextBackgroundColor = blueLeft
customization.guidanceCustomization.buttonFont = fontBody
customization.guidanceCustomization.buttonBackgroundNormalColor = blueLeft
customization.guidanceCustomization.readyScreenTextBackgroundColor = blueLeft
customization.resultScreenCustomization.foregroundColor = blueRight
customization.resultScreenCustomization.activityIndicatorColor = blueLeft.withAlphaComponent(0.8)
customization.resultScreenCustomization.uploadProgressTrackColor = blueLeft.withAlphaComponent(0.8)
customization.resultScreenCustomization.messageFont = fontBody

FaceTec.sdk.setCustomization(customization)

Different environmental conditions

You can apply different settings based on environmental conditions, such as low-light or bright-light situations.

To do this, you must set a unique configuration for each of the scenarios using the FaceTecCustomization object.

  • Default:
    Example: Default configuration
    FaceTec.sdk.setCustomization(customization) // Default
  • Low-light
    Example: Low-light configuration
    FaceTec.sdk.setLowLightCustomization(customization) // low-light
  • Bright-light
    Example: Bright-light configuration
    FaceTec.sdk.setDynamicDimmingCustomization(customization) // bright-light

Multiple controller scenario

For a multiple controller scenario, face authentication must be activated for each controller.