Digipass S3 is now DigipassONE. This section is currently being updated to reflect our new name.

Using the App SDK

Prev Next

The App SDK handles all secure interactions with the Digipass S3 Servers. App SDK methods are asynchronous and do not block the calling thread.

AppSDKSessionData

Most App SDK methods use an AppSDKSessionData object that represents a user's signed-in state. A session token is created when the user signs into your app, after either conventional or FIDO authentication.

Digipass S3 Authentication Software uses a JSON Web Token JWT as its session token. To understand how JWTs are created and used during conventional sign in as well as FIDO authentication, see JWT Session Token.

Conventional authentication

When the user logs in with conventional authentication, like a username and password, then your backend server creates a session token after it verifies the user and returns the token to your app. Your app must insert that session token in an AppSDKSessionData object. Once you've done that, pass that object to any App SDK methods that require an AppSDKSessionData object.

The code below shows how your app can create an AppSDKSessionData object that contains a JWT, highlighted in the example. Hard coding a JWT is not recommended. You can decode the JWT at jwt.io to see its contents or easily modify its values.

let token =
"eyJraWQiOiJoczI1Nl9rZXkiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzbWl0aCIsImF1ZCI6ImRlZmF1bHQiLCJuYmYiOjE1NTczNTc2ODEsImlzcyI6Imh0dHBzOi8vYWNtZS5jb206ODQ0MyIsImV4cCI6MTU1NzM2MTI4MSwiaWF0IjoxNTU3MzU3NjgxfQ.23kj5oj6flVNQl9QDa82XmJdkgHoAdctMY_HmYfZddY"
let sessionData: AppSDKSessionData = AppSDKSessionData()
sessionData.setObject(token, forKey: "sessionKey")

FIDO authentication

After a user registers a FIDO authentication method, they can sign in with Digipass S3’s Adaptive Authentication or FIDO authentication. The App SDK's authentication method returns an AppSDKSessionData object containing a session token. Use this object when you call other App SDK methods that require an AppSDKSessionData object.

In addition to the session token, you can assign the username to AppSDKSessionData's userName attribute. This enables you to pass in a username to App SDK methods that authenticate.

Refer to the AppSDKSessionData class in the Client API Docs for more information.

Setting an active user

To enable certain features to work correctly in the App SDK, you have to let the App SDK know when a user is logged in. After you do this, user data caching and Quick Authentication work properly. In your app, after the user signs in, call setActiveUser() and pass in the username as shown below. This designates the user as an active user. Do this regardless of how the user signs in, in other words, it applies to sign-in using a password, FIDO, SMS OTP, and so on.

NNLAppSDKPlus.setActiveUser(uName)

To ensure a good user experience: When the user logs out, you need to inform the App SDK that there is no longer an active user by using the code below to set the active user to nil.

NNLAppSDKPlus.setActiveUser(nil)

For more information about user data caching, refer to the Client APIDocs.

Extras

The App SDK has a general-purpose mechanism for passing optional data to its methods. It uses a parameter that is a dictionary of key-value pairs, so you can pass in an arbitrary amount of data. The key identifies the type of data. Valid keys are defined in the files IAppSDKPlus.h and AdaptiveMethod.h in the Client API Docs. This parameter is called extras, authOptions, suggestRegOptions, or signUpOptions.

The example below shows how to create the dictionary and specify an account name using the key ExtrasKeyUserName.

var extras = [String: String]()
extras.updateValue("ejohnson@example.com", forKey: ExtrasKeyUserName)

You can find examples of the most common use of extras while performing specific tasks.

Error handling

Error handling depends on if the App SDK method has a completion block or not. Most App SDK methods have a completion block with an error parameter. These methods can be called using await, as described in APIs That Have a Completion Block.

App SDK methods that return a UIViewController are also non-blocking. A UIViewController handles all interaction with the user, including error handling. To customize error handling, you modify the UI, as described in Replacing the Non-FIDO Registration UI and Replacing the Suggest Registration UI. NNLAdaptiveUI.getAuthenticationView() is an exception. This method returns an NNLAdaptiveAuthenticationView, which is derived from UIViewController. Error handling for NNLAdaptiveUI.getAuthenticationView() is described in Authenticating.

APIs that have a completion block

You can use try await when calling the methods in NNLAdaptiveUI or NNLAppSDKPlus that have a completion block parameter. When one of these methods fails, the App SDK writes the error information to the NSError object. Retrieve the status code by calling NSError.code.

The snippet below illustrates how your app can use the FidoStatus and suggest a course of action to the end user.

do {
    try await appsdk.doRegister(session, withExtras: nil)
} catch { 
    //convert to NSError to check the status code
    let err:NSError = error as NSError
    // NSError contains FidoStatusEnum which is the status code 
    // for the process. Use FidoStatusEnum for processing the result
    if (err.code == FidoStatusEnum.USER_LOCKOUT.rawValue) {
        await MainActor.run {
                    messageShowInfo("You've exceeded the maximum allowed attempts to enter your credentials. Please wait 5 minutes and try again.")
                }        
    }
}

See Result codes for the list of possible status codes, including possible resolutions. For a list of methods that could return a status code, refer to the status code documentation for the FidoStatus enum in the file appsdkdef.h in the Client API Docs. The Client API Docs show a short summary for each status code, click on a status code to get full information.

NSError may contain the original exception that caused the error. The nested exception provides more information about the failure. The nested exception is intended for OneSpan support because understanding the content requires knowledge of the internal implementation of the product. Digipass S3 recommends that you always log this information.

In your app, check if there is a nested exception and log the information, as shown below:

do {
    try await //call some SDK process
} catch { 
    //convert to NSError to check the status code
    let err:NSError = error as NSError
    print("Nested exception message is \(String(describing:  err?.userInfo["nestedException"]))")
}

For a full example, refer to traceNestedExceptionStack() in Tutorial App's TAUtils.swift file.

In addition to a status code and depending on the error, NSError can contain additional data that you can use for troubleshooting. This information is intended to be written out to a log for analysis as opposed to examined programmatically. To retrieve this data, call NSError.userInfo["additionalData"]. The code snippet below shows how you can get the status code and write out information to a log.

do {
     try await //call some SDK process
} catch { 
    //convert to NSError to check the status code
    let err:NSError = error as NSError
    //display error message to end user
    // In some cases additionalData contains a detailed explanation of
    // exception cause
   print("Problem while performing the process")
   print("AdditionalData is \(String(describing: err?.userInfo["additionalData"]))")
}

Calling NSError.userInfo["additionalData"] can return a JSON object when available. The following is an example structure with all possible fields. Note that all fields are optional and the JSON object could be null.


{
    "exts":[
        {
            "data": <error info>,
            "fail_if_unknown":false,
            "id": <extensionID>
        }
    ],
    "adaptiveMethod":   <value1>,
    "correlationId":    <value2>,
    "httpStatusCode":   <value3>,
    "nsErrorCode":      <value4>,
    "operationType":    <value5>,
    "serverStatusCode": <value6>
}

For field descriptions, see Fields in the JSON Returned by NSError.userInfo["additionalData"]. The REST API Reference contains information to help you effectively use the values returned in the adaptiveMethod, httpStatusCode, operationType, and serverStatusCode fields.

The important points about error handling are summarized below:

  • Use an try await in your code that calls methods defined on NNLAppSDKPlus or NNLAdaptiveUI classes .

  • When an App SDK method fails, the App SDK writes the error information in the NSError object.

    • To retrieve the status code call NSError.code.

    • Refer to Result codes for status code descriptions and resolutions.

    • In the ClientAPI Docs, check the FidoStatus enum in the file appsdkdef.h for status code documentation.

  • Always write out any additional information contained in the NSError object to a log. Call NSError.userInfo["additionalData"] which returns a JSON.

Fields in the JSON returned by NSError.userInfo["additionalData"]

adaptiveMethod

If an adaptive operation fails because a user wasn't able to verify themselves with an authentication method, NSError.userInfo["additionalData"] can contain an adaptiveMethod JSON object. This object provides more detailed information about why an authentication method failed. An example is shown below:

{
    "adaptiveMethod": {
        "name":"OTP Using Email",
        "type":"Email OTP",
        "state":"FAILED",
        "errorCode":"OTP_INVALID_ERROR",
        "statusHandle":"3ayASVHPzOQWpWwajiLxlKoxDBbmZh0qpUh5DYqshu8"
    }
}

correlationId

correlationId is a unique string value that the App SDK generates. Use this ID to match up related requests and responses between the client and the Authentication Server in the diagnostic log, nnl.log. For example, when your app calls NNLAdaptiveUI.getAuthenticationView(), the App SDK executes several Auth Server  API operations and it  uses the correlationId to tie those operations together.

An example value is shown below:

{
    "correlationId":"ff479909-7420-408e-b494-b6c66bbf1b9c"
}

exts

exts is returned when an authenticator provides additional information when an error occurs. It contains a list of extensions, a general-purpose structure specified by the FIDO standard for passing information between a FIDO Client and ASM. An example extension that returns exception information is shown below:


"exts": [
    {
        "id":"noknok.exception",
        "data":{
            "message":"User canceled operation",
            "name":"asmcore::ASMException"
        },
        "fail_if_unknown":false
    }
]

Each extension must contain the fields listed below.

  • id: String. Name of the extension.

  • data: String. A more informative error. The value is dependent upon the authenticator.

  • fail_if_unknown: Boolean. Indicates whether an unknown extension can be ignored (false) or must lead to an error (true).

Digipass S3 authenticators can return an extension with ID noknok.exception when an error occurs, as shown above. noknok.exception contains a JSON structure with the following fields in its data field:

  • message: Exception information

  • name: Module that threw the error

A custom authenticator that you are using could have been implemented to return error information in an extension. For example, you are using a custom PIN authenticator with a Forgot PIN button that users tap to reset their PIN. When a user taps that button, the PIN authenticator returns a USER_CANCELED error and an extension.

If you are using a third-party custom authenticator, refer to their documentation to see if they return extensions on errors and what values you can expect in those extensions. To create a custom authenticator, contact OneSpan support.

httpStatusCode

This is the status code of the HTTP request returned by the server. If the HTTP status code is 400 or 500, check serverStatusCode for more details. An example value is shown below:

{
    "httpStatusCode":"500"
}

operationType

This field contains the server operation type. Possible values for operationType are:

  • "INIT_ADAPTIVE_REG"

  • "INIT_REG"

  • "FINISH_REG"

  • "INIT_SETUP"

  • "SETUP"

  • "CANCEL_SETUP"

  • "START_OOB_REG"

  • "INIT_OOB_REG"

  • "FINISH_OOB_REG"

  • "CANCEL_OOB_REG"

  • "INIT_ADAPTIVE"

  • "INIT_VERIFY"

  • "VERIFY"

  • "CANCEL_VERIFY"

  • "START_OOB_AUTH"

  • "INIT_OOB_AUTH"

  • "FINISH_OOB_AUTH"

  • "CANCEL_OOB_AUTH"

  • "LIST_REG"

  • "LIST_METHODS"

  • "DELETE_METHODS"

  • "DELETE_REG"

An example value is shown below:

{
    "operationType" : "INIT_ADAPTIVE"
}

nsErrorCode

nsErrorCode contains the error code returned by the system. Use the error code to determine what error on the system caused. An example value is shown below:

{
    "nsErrorCode":"-1003",
}

serverStatusCode

serverStatusCode contains the status code returned by the Authentication Server. For example:

Auth Server Status Code

Description

4409

ClientMessageException

4404

Internal Server Error

Use the status code to determine what error on the server caused the exception. An example value is shown below:

{
    "serverStatusCode":"4409",
}

App IQ

To improve troubleshooting the App SDK includes a built-in error reporting service, App IQ, that is implemented as an NNLErrorReporterListener class. This listener captures operation failures and automatically reports them to the server endpoint of your choosing.

This feature allows an application to:

  • Centralize and standardize error logging.

  • Enrich error data with diagnostic metadata such as device type, OS, and App SDK version.

  • Choose which error codes should or should not be reported. By default, the App SDK reports all error codes except:

    • CANCELED

    • SYSTEM_CANCELED

    • SERVER_USER_NOT_FOUND

For a description of each error code, see iOS Result Codes.

To take advantage of the default behavior, initialize NNLErrorReporterListener:

var listener = NNLErrorReporterListener(
      // your reporting endpoint
      url: "https://errors.example.com/report",
      // API key for authentication
      apiKey: "your-api-key",
      // dynamically resolves the current device ID
      objectIDProvider: { // Can return any NSString
           return NNLAppSDKPlus.getDeviceID()
      },
      // Uses default exclusions (CANCELED, SYSTEM_CANCELED, SERVER_USER_NOT_FOUND)
      disallowedErrorTypes: nil
 )
NNLOperationResultListener.addInstance(listener)

The objectIDProvider is invoked for each error, ensuring that a fresh and accurate device identifier is reported.

To control which error types are excluded from reporting, provide a custom list of FidoStatusEnum values in disallowedErrorTypes:
let disallowed: Set<NSNumber> = [
    NSNumber(value: FidoStatusEnum.CANCELED.rawValue),
    NSNumber(value: FidoStatusEnum.SYSTEM_CANCELED.rawValue),
    NSNumber(value: FidoStatusEnum.SERVER_USER_NOT_FOUND.rawValue),
    NSNumber(value: FidoStatusEnum.FAILURE.rawValue),  // Custom exclusion
    NSNumber(value: FidoStatusEnum.CONNECTION_ERROR.rawValue)  // Custom exclusion
]
let listener = NNLErrorReporterListener(
    url: "https://errors.example.com/report",
    apiKey: "your-api-key",
    objectIDProvider: {
           return NNLAppSDKPlus.getDeviceID()
    },
    disallowedErrorTypes: disallowed
)
NNLOperationResultListener.addInstance(listener)

Because a custom list, disallowed, is provided, the App SDK only reports errors with status code that are not included in disallowedErrorTypes.

Working Example in Tutorial App

  • Refer to file AppDelegate.swift.

Health check service

The App SDK provides an API that checks if the API Server and the Authentication Server are running. This health check service returns real-time status information to your application.

Example usage:

let serverHealthUrl = "$host/nnlgateway/health"
NNLHealthCheck.performHealthCheck(serverHealthUrl).then { result in
            print("HealthCheck result: \(result)")
        } .error() { result in
            print("HealthCheckError: \(result)")
        }

The App SDK returns the health check result as a JSON object. This object contains status codes for both the API Server and the Authentication Server if available.

Example success result:

{
    "apiServer": { "statusCode": 4000 },
    "authServer":{ "statusCode": 4000 }
}

In case of an error, the response will also contain the HTTP status code of the operation.

Example failure result:

{
    "apiServer": { "statusCode": 5601},
    "httpStatusCode": 500
}

For a comprehensive list of possible status codes, see Status Codes.

Working example in Tutorial App

  • Refer to file AppDelegate.swift

Supported authenticators

The App SDK supports all common authentication methods including FIDO UAF authenticators, FIDO2 (CTAP) authenticators FIDO, FIDO using a second device (Out-of-band authentication), SMS OTP, Email OTP, and External Authentication with password and Photo ID. Authenticators store keys in the secure enclave, which is supported on all modern Apple devices, including the watch.

The App SDK includes the following UAF authenticators:

Authenticator Attestation ID (AAID)

Behavior Description

Code to Add Authenticator

4e4e#4005

Legacy Passcode authenticator available on devices that do not support Touch ID / Face ID. Included for compatibility with previous App SDK releases. (iOS 8 and later)

TouchIDASM.addTouchID8Authenticator()

4e4e#4009

Passcode authenticator (iOS 9 and later)

TouchIDASM.addPasscodeAuthenticator()

4e4e#400a

UVS behavior for Touch ID / Face ID authentication (iOS 9 and later)

TouchIDASM.addTouchIDNoLinkageAuthenticator()

4e4e#400b

Key deletion behavior for Touch ID / Face ID authentication (iOS 9 and later)

TouchIDASM.addTouchIDLinkageAuthenticator()

4e4e#400c

Apple Watch authenticator (iOS 10 and later)

WatchASM.addAuthenticator()

4e4e#400e

Yes/No presence authenticator (iOS 9 and later)

PresenceASM.addPresenceAuthenticator()

4e4e#400f

Yes/No presence authenticator (iOS 8 and later)

PresenceASM.addPresence8Authenticator()

4e4e#4014

Ability to use Passcode or Touch ID / Face ID authentication (iOS 9 and later)

TouchIDASM.addTouchIDWithPasscodeAuthenticator()

4e4e#4025

Silent authenticator (iOS 9 and later/watchOS 3.0 and later)

SilentASM.addSilentAuthenticator()

4e4e#4026

Silent authenticator (iOS 8 and later)

SilentASM.addSilent8Authenticator()

4e4e#4027

PIN authenticator (iOS 8)

PinASM.addPin8Authenticator()

4e4e#4028

PIN authenticator (iOS 9 and later)

PinASM.addPinAuthenticator()

4e4e#4093
•••
4e4e#409a

Identical behavior to other authenticators in this table, but with support for credential sharing for keychain sharing.

4e4e#8005

Sample ASM used with the Authenticator SDK when developing a custom authenticator (iOS 8)

SampleASM.addSample8Authenticator()

4e4e#800a

Sample ASM used with the Authenticator SDK when developing a custom authenticator (iOS 9 and later)

SampleASM.addSampleAuthenticator()

Obtaining 3DS data

EMV 3DS is a protocol developed by EMVCo that enables the exchange of data to authenticate the user and prevent fraud, especially during transactions. The App SDK supports this protocol by including the EMV 3DS FIDO blob in the SessionData object that it returns after a successful registration and/or authentication operation.

The App SDK includes the EMV 3DS information inside SessionData only when the API Server's EMV 3DS plugin is active. By default this plugin is active. If you have deactivated this plugin, see EMV 3DS Generator Plugin for instructions to reactivate it.

Once you receive the sessionData, the example below shows how to extract the EMV 3DS data from it.

// FIDO Authentication succeeded. At this point the user is 
// signed in and session is available in authResult.
let sessionData = authResult?.sessionData
// You can extract 3DS data from the sessionData
let emv3ds = sessionData?["emv3dsData"] as? String

To retrieve SessionData after a FIDO registration operation, see Retrieving SessionData. The sessionData object is inside the AuthenticationData object.

To retrieve SessionData after a successful FIDO authentication, see Sign-in Flow or Authentication for Transaction. The sessionData object is inside the AdaptiveResult object. The App SDK includes the EMV 3DS information in SessionData only if the successful authentication rule has Include EMV 3DS Data checked. Otherwise, the value of emv3dsData is null.

For details about the contents of the EMV 3DS FIDO blob, see the Nok Nok™ Data Types Used by the App SDK Tech Note.