The App SDK handles all secure interactions with the Nok Nok Servers.
SessionData
Most App SDK methods use a SessionData 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.
Nok Nok uses a JSON Web Token (JWT) its session token. To understand how JWTs are created and used during conventional authentication as well as FIDO authentication, see JWT Session Token.
Conventional authentication
When the user logs in with conventional authentication like a username and password, 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 a SessionData object. Once you've done that, pass that object to any App SDK methods that require a SessionData object.
The code below shows how your app can create a sessionData 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.
String token =
"eyJraWQiOiJoczI1Nl9rZXkiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzbWl0aCIsImF1ZCI6ImRlZmF1bHQiLCJuYmYiOjE1NTczNTc2ODEsImlzcyI6Imh0dHBzOi8vYWNtZS5jb206ODQ0MyIsImV4cCI6MTU1NzM2MTI4MSwiaWF0IjoxNTU3MzU3NjgxfQ.23kj5oj6flVNQl9QDa82XmJdkgHoAdctMY_HmYfZddY";
SessionData sessionData = new SessionData();
sessionData.put("sessionKey", token);In production, you expect to get the session token from your backend server and use that to create the JWT, as shown below.
SessionData sessionData = new SessionData();
String response = client.getResponse();
JSONObject data = new JSONObject(response).getJSONObject("sessionData");
sessionData.putJsonObject(data)SessionData's putJsonObject() method sets all the fields for the session.
FIDO authentication
After a user registers a FIDO authentication method, they can sign in with Nok Nok's authentication. The App SDK's authenticate() method returns a SessionData object containing a session token. Use that object when you call other App SDK methods that require a SessionData object.
In addition to the session token, you can assign the username to SessionData's userName attribute. This enables you to pass in a username to App SDK methods that authenticate.
Refer to the SessionData 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. This enables user data caching and Registering for Quick Authentication to 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.
AppSDKPlus.setActiveUser("username")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 null.
AppSDKPlus.setActiveUser(null)For more information about user data caching, refer to the Client API Docs.
Extras
The App SDK has a general-purpose mechanism for passing optional data to its methods. It uses a parameter that is a hashmap 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 on the IAppSDKPlus class in the Client API Docs. The parameter that contains the key-value pairs is sometimes called extras, but sometimes it has a descriptive name like authOpts, suggestRegOpts, or signUpOpts.
The example below shows how to create the hashmap and specify an account name using the key EXTRA_KEY_USER_NAME.
HashMap<String, String> extras = new HashMap<>();
extras.put(IAppSDKPlus.EXTRA_KEY_USER_NAME, "asmith@example.com");You can find examples of the most common use of extras while performing specific tasks:
Passing in context data to Adaptive Rules. This calls the extras parameter authOpts.
Passing in a QuickData object during authentication to use Quick Authentication, to bypass the initial round trip. This calls the extras parameter authOpts.
Specifying the QR code type to display for FIDO OOB registration, FIDO OOB authentication, and device blessing.
Error handling
All App SDK methods are non-blocking and return errors in a callback parameter.
App SDK methods that return a fragment do not return errors. A fragment handles all interaction with the user, including error handling. To customize the error handling, you modify the UI, as described in Replacing the FIDO Registration UI or Replacing the Suggest Registration UI. AdaptiveUI.getAuthenticationFragment() is an exception. This method returns an AdaptiveAuthenticationFragment, which is derived from a fragment. Error handling for AdaptiveUI.getAuthenticationFragment() is described in Sign-in.
APIs that use callbacks
Always check to see if an error is passed to a callback. When an App SDK method returns an error, the error information is written to the AppSDKException object. You retrieve the result code by calling AppSDKException.getResultType().
The snippet below illustrates an app using ResultType to check the result code and suggest a course of action to the end user.
AppSdkMethod(... , (resultData, error) -> {
if (error != null) {
if (error is AppSDKException) {
val e: AppSDKException = error
// AppSDKException contains resultType which is the status code for the
// process, which you can use for processing the result
if (e.getResultType() == ResultType.USER_LOCKOUT) {
messageShowInfo("You've exceeded the maximum allowed attempts to enter your credentials. Please wait 5 minutes and try again.");
}
}
}
}See Result Codes and Resolutions for the list of possible result codes, including possible resolutions. For a list of methods that could return a result code, refer to the result code documentation in the ResultType class in the Client API Docs. The Client API Docs shows a short summary for each result code, click on the result code to get full information.
Depending on the error, AppSDKException can contain additional information, in addition to a result code, that you can use for troubleshooting. This information is intended to be written out to a log for analysis, as opposed to examined programmatically. Nok Nok recommends that you always log this information. To retrieve this data, call AppSDKException.getAdditionalData(). The code snippet below shows how you can get the result code and write out information to a log.
AppSdkMethod(... , (resultData, error) -> {
if (error != null) {
if (error is AppSDKException) {
val e: AppSDKException = error
processResult(e.getResultType());
// In some cases additionalData contains a detailed explanation of
// exception cause
Log.w(TAG, "Problem while performing the process" +
((e.getAdditionalData() != null) ? "Additional Data: " +
e.getAdditionalData() : ""));
}
}
}Calling AppSDKException.getAdditionalData() returns 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":[
{
"id": <extensionID>,
"data": <error info>,
"fail_if_unknown":false
}
],
"adaptiveMethod":<value1>,
"correlationID":<value2>,
"httpStatusCode":<value3>,
"operationType":<value4>,
"serverStatusCode":<value5>,
}The fields are described in detail in the subsections below. The REST API Reference contains information to help you effectively use the values returned in the adaptiveMethod, httpStatusCode, operationType, and serverStatusCode fields. The exception field is intended to be used by Nok Nok support for troubleshooting because understanding the content requires knowledge of the internal implementation of the product.
The important points about error handling are summarized below:
Check for errors returned to callback.
When an App SDK method return an error, the App SDK writes the error information in the AppSDKException object.
To retrieve the result code call AppSDKException.getResultType().
Refer to Result Codes and Resolutions for result code descriptions and resolutions.
In the Client API Docs, check the ResultType class for result code documentation.
Always write out any additional information contained in the AppSDKException object to a log. Call AppSDKPlusException.getAdditionalData() which returns a JSON.
Fields in the JSON returned by AppSDKPlusException.getAdditionalData()
adaptiveMethod
If an adaptive operation fails because a user wasn't able to authenticate with a non-FIDO method, then AppSDKException.AdditionalData could contain an adaptiveMethod JSON object. Use this object to provide more detailed information when an authentication method fails. 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 Server in the diagnostic log. For example, when your app calls AdaptiveUI.getAuthenticationFragment(), the App SDK executes several Server REST 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 error information. 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 is shown below:
"exts": [
{
"id": "noknok.exception",
"data": {
"name": "com.noknok.android.client.asm.api.AsmException",
"message": "CANCELED"
},
"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).
Nok Nok authenticators return an extension with ID noknok.exception when an error occurs. This extension contains nested exception information in a JSON structure with the following fields in its data field:
name: Module that threw the error
message: Exception information
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 Nok Nok 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"
An example value is shown below:
{
"operationType" : "INIT_ADAPTIVE"
}serverStatusCode
serverStatusCode contains the status code returned by the Authentication Server. For example:
Auth Server | 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"
}Error handling for the native fingerprint ASM
Your app needs to properly handle the special error case for the Native Fingerprint ASM. In the Native Fingerprint ASM, user keys are generated and stored in the KeyStore. The keys are invalidated when a new fingerprint is added to the device. This behavior helps prevent unauthorized access to existing FIDO credentials by someone who obtains the device and tries registering their fingerprint.
Below is the result code returned in the special error case:
Authenticate (Regular) | Authenticate (Checking if Authentication is Possible) |
|---|---|
KEY_DISAPPEARED_PERMANENTLY | SUCCESS |
Refer to Result Codes and Resolutions for more details about AppSDK result codes.
In the error case, a regular authenticate operation returns KEY_DISAPPEARED_PERMANENTLY, whereas checkAuthPossible() returns SUCCESS. When KEY_DISAPPEARED_PERMANENTLY is returned, the authenticator automatically removes the FIDO credential. Your app can then register a new FIDO credential.
Once the fingerprint set change is detected by the above return codes, your app might need to allow the user to create a new FIDO credential. The following diagram depicts the overall calling sequences for the case of fingerprint set change:
.png?sv=2026-02-06&spr=https&st=2026-09-30T03%3A52%3A40Z&se=2026-09-30T04%3A15%3A40Z&sr=c&sp=r&sig=2JTE8RsqOWUQdk08RSHXV5TiDByAjM%2BxamBuSgNCk%2BQ%3D)
App IQ
To improve troubleshooting the App SDK includes a built-in error reporting service, App IQ, that is implemented as an ErrorReporterListener 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 Android Result Codes.
To take advantage of the default behavior, initialize ErrorReporterListener, supplying the endpoint for your reporting system server, the tenant-specific API key, and an ObjectIDProvider:
val errorListener = ErrorReporterListener(
this,
"https://errors.example.com/report",
"your-api-key",
ObjectIDProvider { // Dynamic Object ID retrieval logic
"dynamic_object_id_value"
},
null)
OperationResultListener.addInstance(errorListener)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 disallowed result types:
val disallowedList = setOf(
ResultType.CANCELED,
ResultType.SYSTEM_CANCELED,
ResultType.SERVER_USER_NOT_FOUND,
ResultType.FAILURE)
val errorListener = ErrorReporterListener(
this,
"https://errors.example.com/report",
"your-api-key",
ObjectIDProvider { // Dynamic Object ID retrieval logic
"dynamic_object_id_value"
},
disallowedList)
OperationResultListener.addInstance(errorListener)The App SDK only reports errors with status code that are not included in disallowedList.
Working example in Tutorial App
Refer to file TutorialAppPlus.kt
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:
val serverHealthUrl = "$host/nnlgateway/health"
HealthCheck.performHealthCheck(this, serverHealthUrl)
.then { result ->
println("HealthCheck result: $result")
}.error { error ->
println("HealthCheckError: $error")
}
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, along with the HTTP status code of the response.
Example result:
{
"apiServer":{"statusCode":4000},
"authServer":{"statusCode":4000},
"httpStatusCode":200
}For a comprehensive list of possible status codes, see Status Codes.
Working example in Tutorial App
Refer to file TutorialAppPlus.kt
Supported authenticators
The App SDK supports all common authentication methods including FIDO2 (CTAP) authenticators FIDO UAF authenticators, FIDO using a second device (Out-of-band authentication), SMS OTP, Email OTP, External Authentication with password, and Photo ID.
The App SDK includes the following UAF authenticators:
Authenticator | Authenticator Attestation IDs (AAID) |
|---|---|
Class 3 Biometric | 4e4e#4010, 4e4e#4012, 4e4e#4013, 4e4e#4018, 4e4e#4038, 4e4e#403a, 4e4e#40a1 |
Class 2 Biometric | 4e4e#40aa, 4e4e#40ab, 4e4e#40ac, 4e4e#40ad, 4e4e#40ae, 4e4e#40af |
Lock Screen | 4e4e#401e, 4e4e#401f, 4e4e#4020, 4e4e#4021, 4e4e#4022, 4e4e#4023, 4e4e#403c, 4e4e#403d, 4e4e#40a2, 4e4e#40a3 |
PIN | 4e4e#4006, 4e4e#4015, 4e4e#4019, 4e4e#4037, 4e4e#403b, 4e4e#40a0 |
Presence | 4e4e#400d, 4e4e#4017, 4e4e#401b, 4e4e#4030, 4e4e#4032, 4e4e#40a4 |
Sample | 4e4e#4016, 4e4e#401a, 4e4e#4003, 4e4e#4031, 4e4e#4035, 4e4e#4008, 4e4e#40a6 |
Silent | 4e4e#403f, 4e4e#4040, 4e4e#4090, 4e4e#4091, 4e4e#4092, 4e4e#40a5 |
Wear OS watch | 4e4e#40b0 |
Silent Reg | 4e4e#40b7, 4e4e#40b8, 4e4e#40b9, 4e4e#40ba, 4e4e#40bb, 4e4e#40bc |
For many devices running Android API 29 or earlier, users encountered failures because that biometric prompt offers weak biometrics. In the Nok Nok Android App SDK 8 and later, for Android API 29 or earlier, the Nok Nok class 3 biometric authenticator uses the Android Fingerprint API by default to avoid these failures. However, Nok Nok has identified certain devices where the Android Fingerprint API has issues. On these devices, the biometric prompt is employed instead.
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 sessionData, the example below shows how to extract the EMV 3DS data from it.
//Get the login session token, for subsequent App SDK calls
sessionData = authResult.sessionData;
// Retrieve the EMV 3DS blob from session data, it is null if the
// successful adaptive rule does not support EMV 3DS
String emv3dsData = sessionData.get("emv3dsData");To retrieve SessionData after a FIDO registration operation, see Retrieving SessionData. To retrieve SessionData after a successful FIDO authentication, see Sign-in flow. The sessionData object is inside an AuthenticationData 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.