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

Implementing authentication in your app

Prev Next

This section covers how you can add FIDO authentication to your mobile app. Authentication Lifecycle shows how to implement FIDO registration, authentication and transaction confirmation including high level APIs for Sign-in, Sign-up and Transaction flows. The remaining sections focus on additional, common features that you can add to enhance your app's authentication functionality.

If your target usage scenario doesn’t require certain features, you can safely ignore them and their accompanying documentation. Note that adding features that won’t be used can unnecessarily increase the size of your app.

The following table outlines individual App SDK features along with the benefits of including them with your app.

Feature

Benefits

Out-of-Band (OOB) authentication

Enables a mobile device to provide FIDO authentication for a web app running on a non-FIDO device, such as a desktop without FIDO2 authenticators. Required for using the Device Blessing feature; not available in FIDO2.

See Out-of-Band Authentication.

Quick Authentication

Improves a user's authentication experience in areas with slow networks or on a low-bandwidth device.

See Registering for Quick Authentication.

Device blessing

Allows provisioning a new device from an existing device; depends on OOB functionality.

See Device Blessing Support.

Phone as a roaming authenticator

A phone can be a roaming authenticator for FIDO2 apps by using Bluetooth Low Energy (BLE). Requires that your FIDO2 web app runs in a FIDO2-enabled desktop browser on a Windows computer.

See Using a Phone as a Roaming Authenticator.

FIDO credential sharing across multiple mobile apps

When you have multiple mobile apps, you can designate one app to perform authentication for all of the related apps. This is possible because FIDO credentials are shared among the apps.

In this scenario the user registers once using the designated authentication app and does not have to register in any of the other apps. The designated app owns and manages the FIDO credentials for the related apps.

See Using Passport App for Credential Sharing.

WebView Integration

Allows your mobile app to support authentication within an embedded WebView.

See Embedding a WebView.

Authenticator selection

Allows you to control the authenticators shown to the user when they register or authenticate.

See Controlling Authenticator Selection.

Manage personally identifiable information

Allows you to retrieve a user's active and inactive registrations. Enables you to delete a user's registrations and their history of FIDO operations.

See Managing Personally Identifiable Information (PII).

External Authentication

Allows your users to authenticate with passwords and any other authentication method not currently supported by Nok Nok.

See Using an External Authentication Method.

Authentication lifecycle

Overview

Using your app, a user must register a FIDO authenticator, SMS OTP, Email OTP, and/or Photo ID. These are referred to collectively as authentication methods. Typically, a FIDO authenticator is a biometric embedded in the device, such as a fingerprint, face, or voice authenticator.

On subsequent logins and transaction confirmations, your app prompts the user to verify their identity (or authenticate) using one or more of their registered authentication methods.

When you call the App SDK authentication methods suggested here, the Server performs Adaptive Authentication, taking into account any signals or context data that your app provides. The Server returns a list of authentication sequences appropriate for the user's current situation that satisfy your organization's criteria for strong authentication. The App SDK guides the user to complete one authentication sequence. As a result, your app need only check whether authentication succeeds or fails, then take any appropriate actions.

After getting registration and authentication working, you can expand your app's capabilities.

  • You can suggest that new users register authentication methods necessary for strong authentication instead of continuing to rely on passwords. This capability uses Nok Nok's Adaptive Registration, which, like Adaptive Authentication, determines a set of vetted authentication methods and guides the user to register the methods in one registration sequence.

  • You can allow users to manage their registrations or rename their authentication methods after registering.

  • If your app's users can perform transactions, you can implement transaction confirmation using Adaptive Authentication.

Prior to deploying your app, make sure that you define FIDO policies and Adaptive Rulesets on the Server, since these objects encapsulate your organization's criteria for strong authentication. See Configure Adaptive Rulesets. Nok Nok provides a default FIDO policy and Adaptive Ruleset that you can use initially.

Most App SDK methods require a SessionData object that represents a user's signed-in state. For a detailed explanation of what this is and how to create it, see SessionData.

Development approach

The goal of this page is to help you quickly implement FIDO in your app. As a result, it covers high-functioning App SDK methods that return fragments that you insert into your app's UI. These fragments handle all user interaction as well as work with the Authentication Server. Nok Nok designed these fragments to be flexible so you can replace the UIs. There are lower level APIs that you may decide to use instead, these are documented in the Client API Docs.

When you implement FIDO in your app, use the following recommended approach:

  1. Verify that your development environment is set up correctly by successfully building Tutorial App.

  2. Configure your Authentication Server to work with Tutorial App. You should be able to successfully register and authenticate using Tutorial App.

  3. When you know that your environment and Auth Server configurations work correctly, use the classes and methods described on this page to implement registering and sign-in. This allows you to focus on implementing core functionality. It also eliminates the UI as a potential source of bugs.

  4. Expand your app's FIDO capabilities by suggesting authentication methods to register, managing registrations, implementing out-of-band authentication, and so on using the classes and methods recommended here.

  5. When you have FIDO functionality working in your app with your Auth Server configuration, replace the default UIs with your desired UIs. See Replacing the UI.

Handling Activities

Some of the App SDK methods may internally switch to a background thread. For example, the App SDK switches to a background thread to complete a network operation. However, Android may destroy activities under certain circumstances. For example, Android can destroy an activity when the device is low on memory or the Activity's configuration changes. For this reason it is not safe to pass in a direct reference to an Android Activity. Instead, create a Nok Nok ActivityProxy object in the foreground thread, and pass the ActivityProxy to an App SDK method.

There are two different ways to create an ActivityProxy for a given Activity:

  1. Call ActivityProxy.createFromActivity() creates an invisible activity and returns the ActivityProxy. Once your background thread is finished with the ActivityProxy, your background thread must call ActivityProxy.finish(). This solution does not require the modification of your Activity.

  2. A better way to create an ActivityProxy is to modify your current Activity. Inside your Activity's onCreate(), onSaveState(), and onDestroy() methods, add calls to ActivityProxy methods. Then your Activity can save the ActivityProxy and pass it to the background thread. In this case, the background thread should not call ActivityProxy.finish().

For more information on class ActivityProxy, see the Client API Docs.

Working example in Tutorial App

  • Refer to file MainActivity.kt

Creating the main objects

To implement FIDO functionality, your app primarily uses methods defined on 2 App SDK classes: AdaptiveUI and AppSDKPlus. Call AdaptiveUI methods to perform Adaptive Registration, Adaptive Authentication, and register OTP and Photo ID authentication methods. Call AppSDKPlus methods to register FIDO authenticators, manage a user's registrations, and accomplish other tasks described in here. Your app needs to start by creating instances of these 2 classes.

AdaptiveUI methods send requests to the endpoints for registration and authentication. These URLs must be specified in a configuration object, called AppSDKPlusConfig, that you pass to AdaptiveUI's constructor, as shown below. In addition, you must specify which protocol, UAF, FIDO2, or BOTH, that AdaptiveUI's methods will use. The protocol type BOTH is intended to be used for Adaptive Registration and Adaptive Authentication. The code below shows how to do this.

// Create configuration object with the registration and authentication 
// endpoints regUrl and AuthUrl.
regURL = "https://<nnl_apiserver_domain>:<port>/nnlgateway/nnl/reg";
authURL = "https://<nnl_apiserver_domain>:<port>/nnlgateway/nnl/auth";
AppSdkPlusConfig config = new AppSdkPlusConfig(regUrl, authUrl, 
                                               null, false);
// Specify whether you are using UAF, FIDO2, or BOTH protocol. If your
// Adaptive Registration and Adaptive Authentication Rules include
// UAF and FIDO2 authenticators in their sequences, use BOTH.
config.setProtocolType(ProtocolType.BOTH);
AdaptiveUI adaptiveUI = new AdaptiveUI(config);

To create an instance of AppSDKPlus, you also create and configure an AppSDKPlusConfig object as shown above.

// Initialize the configuration object
AppSdkPlusConfig appSdkPlusConfig = new AppSdkPlusConfig(regUrl, authUrl, null, false);
appSdkPlusConfig.setProtocolType(ProtocolType.UAF);
// Create an AppSDKPlus object
AppSDKPlus appSDKPlus = new AppSDKPlus(appSdkPlusConfig, context);

Working examples in Tutorial App

  • AuthTypes.kt: Shows how to configure AppSdkPlusConfig.

  • MainActivity.kt: Creates an AppSDKPlus object.

  • RegControllerFragment.kt: Creates an AdaptiveUI object.

Registering

Prior to authenticating, you have to register a FIDO authenticator, SMS OTP, email OTP, or Photo ID. The App SDK provides 3 customizable fragments so you can get registration working faster in your app.

  • To register a FIDO authenticator: Initialize the AppSDKPlus for UAF and use AppSDKPlus.getRegistrationFragment(). This method returns a fragment, shown below. This object contains functionality to view, register, and deregister UAF authenticators.
    Fragment showing 5 unregistered UAF authenticators: Biometric, PIN, Yes/No, Device, and Screen Lock.

  • To register FIDO2 authenticators: Initialize the AppSDKPlus for FIDO2 and use AppSDKPlus.getRegistrationFragment(). This method returns a fragment, shown below. This object contains functionality to register FIDO2 authenticators.

  • To register non-FIDO methods such as OTP or Photo ID: Use AdaptiveUI.getRegistrationFragment(). This method returns a fragment object, shown below. This object contains functionality to view, register, and deregister non-FIDO authentication methods.
    Fragment showing 3 non-FIDO authentication methods that can be registered: Email OTP, Photo ID, and SMS OTP.

    Both OTP and Photo ID require configuration on the Server. SMS OTP and Photo ID require 3rd party services. See Configure non-FIDO authentication methods.

The list of authentication methods presented to the user are controlled by the Adaptive Rulesets (for AdaptiveUI.getRegistrationFragment()) and FIDO policies (for AppSDKPlus.getRegistrationFragment()) on the Authentication Server. The list of methods is further refined based on the capabilities of the device. This results in showing the user the right options based on the context.

Registering FIDO authenticators

Prior to authenticating with FIDO, you have to register a FIDO authenticator credential. The fragment object created by calling AppSDKPlus.getRegistrationFragment() works with either FIDO UAF authenticators or FIDO2 authenticators, but not both.

When you create the AppSDKPlus object, you specify the protocol. To allow users to work with both UAF and FIDO2 authenticators, create 2 AppSDKPlus objects each using a different protocol.

appSdkPlusConfig.protocolType = ProtocolType.FIDO2
val fido2AppSDKPlus: IAppSDKPlus = AppSDKPlus(appSdkPlusConfig, appContext)

After creating the AppSDKPlus object, get the session object that was created during sign in, see SessionData.

Next, create a fragment by calling getRegistration Fragment , passing in the SessionData object. During registration, you can allow the user to assign a recognizable name to their account, instead of using the UUID. This can only be done at registration and there is no way to rename the account later. The account name is stored locally by the authenticator, not on the Authentication Server.

After the user has entered the desired account name, pass it to AppSDKPlus.getRegistrationFragment() in its extras argument, using EXTRA_KEY_USER_NAME as the key. You can also assign the display name, a friendly local name, using the key EXTRA_KEY_USER_DISPLAY_NAME.

There may be situations where you don't want to display a user name, for example, your system generates a unique randomly-generated name for each account. In this situation, use IAppSDKPlus.EXTRA_KEY_USER_DISPLAY_NAME to assign a "friendly" user name to the registered credential. During authentication, the device displays the "friendly" name on the platform UI and Conditional UI. For more information, see WebAuthn Credential Selection UI.

HashMap<String, String> extras = new HashMap<>();
extras.put(IAppSDKPlus.EXTRA_KEY_USER_NAME, "ejohnson@example.com");
extras.put(IAppSDKPlus.EXTRA_KEY_USER_DISPLAY_NAME, "Emily");
val fido2RegisterFragment = 
    fido2AppSDKPlus.getRegistrationFragment(sessionData, extras);

If you need 2 fragments, one for UAF and the other for FIDO2, call getRegistrationFragment() on each of the AppSDKPlus objects you created.

If the Auth Server doesn't return any UAF authenticators, the fragment contains the message "No methods available to register". This can never be the case for FIDO2 authenticators.

Insert the registration Fragment in your page, this should be done from the UI thread.

childFragmentManager
    .beginTransaction()
        .replace(container_fragment_id, fido2RegisterFragment)
    .commit()

You can create a custom UI for FIDO registration, refer to Replacing the FIDO Registration UI.

Working Example in Tutorial App
  • RegControllerFragment.kt: Demonstrates registration.

Registering other (non-FIDO) authentication methods

After creating the AdaptiveUI object, get the SessionData object that was created during sign in, see SessionData. Pass in the SessionData object to AdaptiveUI.getRegistrationFragment(). getRegistrationFragment() uses Adaptive Registration to determine allowed authentication methods that a user can register. To pass in context data to Registration Decision Rules, use the extras parameter. See Sending Signals and Passing in Context Data.

FragmentTransaction transaction = 
    getChildFragmentManager().beginTransaction(); 
AdaptiveUI adaptiveUI =
    new AdaptiveUI(TutorialAppPlus.getAuthType().getAppSdkPlusConfig()); 
Fragment fragment = 
    adaptiveUI.getRegistrationFragment(sessionData, extras); 
transaction.replace(R.id.fl_adaptive_register, fragment); transaction.commit();

If the Auth Server doesn't return any non-FIDO authentication methods, the fragment contains the message "No methods available to register".

Insert the registration fragment into your page, this should be done from the UI thread. When the user selects an authentication method, the registration fragment prompts the user to enter the necessary information, such as the email address for email OTP.

You can create a custom UI for registering authenticators, refer to Replacing the Non-FIDO Registration UI.

Working Example in Tutorial App
  • Refer to file RegControllerFragment.kt

Retrieving SessionData

Sometimes you need to retrieve the SessionData object from a FIDO registration operation. To do this, create a mechanism that passes the SessionData to your callback function. Take the following steps:

  1. Create a custom object that implements the IFidoRegistrationListener interface.

  2. Get the FidoRegisterController instance from the View.

  3. Call FidoRegisterController.setListener() and pass in an instance of the IFidoRegistrationListener object.

  4. After successful registration, FidoRegisterController calls your onRegisterCompleted() function and passes in an AuthenticationData object containing sessionData.

// Kotlin implementation of IFidoRegistrationListener interface.
// This sample just logs parameters when corresponding method is called.
class SampleFidoRegistrationListener(private val mContext: Context): IFidoRegistrationListener {
    override fun onRegisterCompleted(authData: AuthenticationData?) {
        Log.i("Sample", "Fido registration successfully completed: $authData")
    }
    override fun onRegisterFailed(result: ResultType?) {
        Log.e("Sample", result!!.getMessage(mContext))
    }
    override fun onDeregisterFailed(result: ResultType?) {
        Log.e("Sample", result!!.getMessage(mContext))
    }
}
// Get the FidoRegisterFragment instance.
uafRegisterFragment = uafAppSDKPlus.getRegistrationFragment(
                          appContext, sessionData, extras) as FidoRegisterFragment
// Pass in a new instance of the listener to the controller.
uafRegisterFragment.controller.setListener(
                                 SampleFidoRegistrationListener(requireContext()))

For more information on the IFidoRegistrationListener and the FidoRegisterController, see the Client API Docs.

Registering for Quick Fido Authentication

Users on slow networks or using low-bandwidth devices can experience a delay before seeing the first FIDO authentication screen. Before FIDO authentication can start, normally a round trip between the App SDK and the Server is required to determine what authentication methods should be used. You can improve your users' experience by enabling Quick Authentication, which bypasses the initial round trip.

When you enable Quick Authentication during registration, the Server sends back the information that the App SDK needs to generate the challenge for authentication. You store this information so it persists. To authenticate, pass this information to the Server.

Enable Quick Authentication when you register by passing a boolean flag to AppSDKPlus.getRegistrationFragment() in extras. Use EXTRA_KEY_QUICK_ENABLE as the key and "true" as the value.

// Assign true to the key EXTRA_KEY_QUICK_ENABLE
extras[IAppSDKPlus.EXTRA_KEY_QUICK_ENABLE] = "true";
val registerFragment = appSDKPlus.getRegistrationFragment(appContext, sessionData, extras);

The App SDK uses a QuickData object that encapsulates the necessary data to generate the challenge. If the user registered more than one FIDO authenticator while they used the Fragment, the QuickData object is tied to the last FIDO registration that the user made. This object is valid for the lifetime of the registered authenticator. QuickData is automatically saved in the user data cache. Your app can optionally provide a name for storing and retrieving this QuickData:

// provide alternative quick data key for shared preferences
extras[IAppSDKPlus.EXTRA_KEY_QUICK_AUTH_DATA_KEY_NAME] = "FIDO_ONLY"

  • Using Quick Authentication can result in inconsistent behavior because the SDK is not initially consulting a ruleset, but the Server is still enforcing the ruleset.

  • Both UAF and FIDO2 authenticators can take advantage of Quick Authentication.

  • When using an external authentication method, enabling Quick External Authentication is also supported when you use Sign-in flow, though external authenticators are not registered.

  • The S3 Suite must be configured for Quick Authentication. See Quick Authentication.

Working examples in Tutorial App

  • ExtrasHelper.kt: The setQuickAuth() method sets the extra values required for Quick Authentication.

  • RegControllerFragment.kt: Search for TutorialAppPlus.useQuickAuth to see sample code that generates a QuickData object for a registration made when calling AppSDKPlus.getRegistrationFragment().

Prompting the user to name a security key

Some users have more than one security key, so a security key name can help the user identify one. When the user is registering a security key, your app can prompt the user to name this new authenticator. When you call getRegistrationFragment(), add the key IAppSDKPlus.EXTRA_KEY_ASK_CREDENTIAL_NAME with the value "true" to the extras parameter.

val extras: HashMap<String, String> = HashMap()
extras[IAppSDKPlus.EXTRA_KEY_ASK_CREDENTIAL_NAME] = "true"
val fragment = AppSDKPlus(config, requireContext()).getRegistrationFragment(
            requireActivity().applicationContext, Model.sessionData, extras
        )
Working Example in Tutorial App
  • Refer to file RegControllerFragment.kt.

Suggesting authentication methods to register

New end users may not be aware that they should register a FIDO authenticator on their device. Your app can automatically prompt users to register a FIDO authentication method after they sign in with a password. The App SDK assesses what authentication methods to suggest based on the Registration Decision Rules that you define on the Authentication Server.

The built-in Suggest Registration UI:

  • Displays this view. The choices depend on the active Registration Decision Rules.

  • If the user taps an authentication method to register, the App SDK automatically prompts the user to complete that registration. If registration is successful, the user doesn't see this UI again.

  • If the user taps Never ask me again, then the App SDK closes the dialog and the user is never shown this UI, even if they never register a FIDO authenticator.

  • If the user taps Not Now, then the App SDK closes the dialog. If the user signs in with a password in the future, they see this UI again.

When using the full Sign-in flow, trigger the Suggest Registration UI by simply setting a flag. To trigger this functionality when not using the sign-in flow, call AdaptiveUI.suggestRegisterAsync() explicitly:

  1. After creating the AdaptiveUI object, get SessionData.

  2. Fill in the extras HashMap with additional information like context data for Registration Decision Rules, the account name, and user name. See Sending Signals and Passing in Context Data and Registering FIDO Authenticators.

  3. Call suggestRegisterAsync(). Pass in the callerActivityProxy, sessionData, extras, and completion callback to suggestRegisterAsync().

  4. Include the method call in a try/catch block.

try { 
    adaptiveUI.suggestRegisterAsync(callerActivityProxy, sessionData, extras, ((result, error) -> {
        // the operation completion processing should be done here
        callerActivityProxy.finishAsync();
    }));
} catch (AppSDKException e) { 
    // AppSDKException contains resultType which is the status code for the
    // process, which you can use for processing the result
}

The result parameter is an AdaptiveResult object which contains the result of the registration operation. For more information about error handling, see Error Handling.

If the user deletes all of their registrations, you can reset the Suggest Registration UI so it prompts the user to register an authentication method. Call the resetSuggestRegister() method:

adaptiveUI.resetSuggestRegister(context);

Automatically create a passkey

There are two ways to enable the App SDK to silently create a passkey for the user:

  1. Create a FIDO policy that allows the UAF authenticator called SilentReg.
    A SilentReg authenticator does not require user verification during registration, but it does require biometric user verification during authentication. The App SDK already contains the SilentReg authenticator metadata, but you need to Create a policy that uses this UAF authenticator.

  2. Enable the FIDO2 WebAuthn feature “conditional-create” on either the server or the client:

    1. Server: To enable this feature without writing additional code, add a FIDO policy on your Digipass S3 Authentication Server. In the Server Admin Console, navigate to Authentication > FIDO Policies and add a FIDO policy. On the Policy Details page, open the Additional Features panel. Click Allow next to Automatically Create Passkey.

    2. Client: Set the EXTRA_KEY_USER_MEDIATION field in the extras parameter before calling any of the following functions from class AdaptiveUI: getRegistrationFragment(), suggestRegister(), register().

      regOpts[IAppSDKPlus.EXTRA_KEY_USER_MEDIATION] = IAppSDKPlus.USER_MEDIATION_CONDITIONAL

If the App SDK successfully creates a passkey using conditional-create, and your Server's adaptive ruleset requires no more methods for registration, then the App SDK will not show any UI but the Google Password Manager displays the following message:

If your Server's adaptive ruleset does require the user to register more methods, then that user interface starts automatically.

Sign-in

The Nok Nok SDK implements the Sign-in flow to simplify integration with your application. Your app sets the authentication options and creates the View. Then when your app calls enable(AutoStart.SIGN_IN), the SDK interacts with both the user and the Authentication Server to either successfully authenticate the user or report that authentication is not possible. You can create a custom UI for this authentication process, see Replacing the Authentication UI.

When your app calls enable(AutoStart.SIGN_IN), the SDK opens the view with the user name field and Next button to start authentication. The Next button checks if there is an authentication sequence that only contains a single authenticator. If so, it verifies the user's identity with that authenticator. If not, then it displays a list of available authentication methods. The SDK can also optionally trigger Suggesting Authentication Methods to Register if the user hasn't yet done so. The enable() method returns a Promise object.

The following code performs the whole Sign-in flow. A description of each step follows.

// Step 1: Set authentication options
val authOpts: HashMap<String, String> = HashMap()
authOpts[IAppSDKPlus.EXTRA_KEY_USER_NAME] = "userName"
// Step 2: Optionally set suggest registration options
val suggestRegOpts = HashMap<String, String>()
suggestRegOpts[IAppSDKPlus.EXTRA_KEY_SUGGEST_REG_ENABLED] = "true"
// Step 3: Create the Fragment
val fragment = AdaptiveUI(appSdkPlusConfig).getAuthenticationFragment(
       SessionData, null, authOpts, suggestRegOpts, null)
// Step 4: Trigger authentication
fragment.controller.enable(Activity, AutoStart.SIGN_IN)
.then ({ authResult in
    // At this point the user is signed in and the session is available.
    // Step 5: Process the result
    val sessionData = authResult?.sessionData
    // You can extract username from profileData.
    val profileData = authResult?.profileData 
    val userName = profileData[AuthenticationData.USER_NAME]?
    completedMethods = authResult.completedMethods
})

To trigger this sign-in flow, your application takes the following steps:

  1. Use the optional authOpts to pass in the preferred user name. The SDK uses this to automatically fill the username field on the sign-in page. Also use authOpts to pass in additional information like context data needed by Authentication Rules. See Sending Signals and Passing in Context Data. If you are implementing Quick Authentication, use authOpts to indicate your preferred Quick Mode.

  2. After sign in, you can optionally have the SDK automatically suggest to users that they register a passwordless authenticator. See Suggesting Authentication Methods to Register. Note that you can pass in a different set of authentication options in the suggestRegOpts for the SDK to use for the Suggest Registration operation.

  3. Create the Fragment for authentication by calling AdaptiveUI.getAuthenticationFragment(). As in registration, you should immediately insert this View into your app's view.

  4. Trigger authentication for the user by calling enable(Activity, AutoStart.SIGN_IN).
    The call to enable(Activity, AutoStart.SIGN_IN) gets the username, makes every attempt to authenticate the user, optionally suggests that the user register an authenticator, and returns a Promise object. If the user is not able to authenticate, the SDK redisplays the sign-in page.

  5. If the user successfully authenticates, the promise resolves and returns an AdaptiveResult object containing the result of the authentication operation. AdaptiveResult includes the session data object, AppSDKSessionData, as well as additional session and username information, which you can retrieve.

    • Enable passkey support to allow your users to seamlessly share their credentials across your website and your Android application. See Enabling FIDO2 for instructions.

    • You may want to use your legacy sign-in flow combined with the Nok Nok sign-in flow. To do this, your app prompts for the username and then decides whether to use your legacy authentication flow or the Nok Nok sign-in flow. In the case where you use the Nok Nok sign-in flow, your app then calls enable() with an AutoStart mode other than AutoStart.SIGN_IN. When you call enable() with any other AutoStart mode, the SDK skips the username prompt. For more details, ask Nok Nok customer support about Legacy Authentication.

      For more information on the AdaptiveUI, AuthenticationController, and AdaptiveResult classes and methods, see the Client API Docs. For more information on options, see class IAppSDKPlus in the Client API Docs.

Working example in Tutorial App

  • Refer to MainActivity.kt which shows how to call enable(Activity, AutoStart.SIGN_IN).

WebAuthn credential selection UI

To streamline the user's experience when they authenticate with a passkey, the SDK supports a new WebAuthn mode called "Conditional UI". When you enable this mode, the SDK displays user credentials on the initial sign-in screen. If the user has already registered a multi-device passkey, the SDK shows the Authenticate with a passkey button. If the user presses the button, it shows a list of credentials for the user to choose from. You can only take advantage of this feature when you use the Sign-in flow.

To enable conditional UI mode, set USER_MEDIATION_CONDITIONAL as the value for the EXTRA_KEY_USER_MEDIATION in the authOpts parameter before calling getAuthenticationFragment().

val authOpts = HashMap<String, String>()
authOpts[IAppSDKPlus.EXTRA_KEY_USER_MEDIATION] = USER_MEDIATION_CONDITIONAL

Now if there is a registered passkey that is synchronized with a Google account, the SDK shows an additional Authenticate with a passkey button during sign-in.

Important Notes:

  • In order to use any FIDO2 authenticators, including passkeys, you must enable FIDO2 for your app. See Enabling FIDO2

  • Your users can employ third party credential providers in addition to multi-device passkeys synchronized with a Google account. Be sure that credentialManagerEnabled is true - it is enabled by default - so that the App SDK uses CredentialManager APIs in your application to support this feature.

Implementing Quick Authentication

When using Sign-in flow, you can eliminate the initial interaction with the Authentication Server by registering for Quick Authentication and then implementing it during authentication. After Quick Authentication, if the server requires additional authentications to be performed then the SDK prompts the user to perform those additional authentications.

Before calling getAuthenticationFragment(), specify a value for EXTRA_KEY_SIGN_IN_QUICK_MODE in the authOpts parameter.

val authOpts: HashMap<String, String> = HashMap()
authOpts[IAppSDKPlus.EXTRA_KEY_SIGN_IN_QUICK_MODE] = "QUICK_FIDO_ONLY"

If your app provided a name for the QuickData object when it registered for Quick Authentication, then include that name as the value for the EXTRA_KEY_QUICK_AUTH_DATA_KEY_NAME key in authOpts.

The table below describes the Quick Authentication modes. Choose your mode and assign the corresponding value to EXTRA_KEY_SIGN_IN_QUICK_MODE:

Value

Description

QUICK_FIDO_ONLY

If Quick FIDO authentication is enabled for this user then the SDK prompts for FIDO authentication first.

QUICK_FIDO_OR_EXTERNAL

If Quick FIDO authentication is enabled for this user then the SDK prompts for FIDO authentication first. If the user cancels, then the SDK shows a list with FIDO and External Quick Authenticators.

QUICK_EXTERNAL_AND_FIDO

If an External Authentication Method is configured then this option prompts for the External Authenticator first. If this is successful, then the SDK prompts the user with a FIDO Authenticator if available.

QUICK_EXTERNAL_ONLY

If an External Authentication Method is configured then this option prompts for the External Authenticator first.

QUICK_NONE

Default value. No Quick Authentication is done.

If you do not register a FIDO authenticator for Quick Authentication, you can still specify a quick authentication mode during Sign-in flow and all subsequent FIDO authentications bypass the initial round trip to the server. If you did not configure External Authentication for the app, then the App SDK ignores the modes requiring External Authentication.

You must configure the S3 Suite for Quick Authentication. See Quick Authentication.

Also see Enabling Quick FIDO Authentication in the Tutorial App.

Working example in Tutorial App

  • Refer to Controller.kt, QuickTypePreferences.kt, and SettingsFragment.kt to see how to set EXTRA_KEY_SIGN_IN_QUICK_MODE.

Provide the time used for Quick Auth

By default the Nok Nok SDK relies on the user's device time when it generates a challenge for Quick Authentication. But if the user's device time is not correct, Quick Authentication can fail. To prevent that failure, your application can provide the current time to the Nok Nok App SDK.

To provide a synchronized current time to the Nok Nok App SDK, your application implements the ITimeProvider interface and calls TimeProviderManager.setInstance() during initialization of your app.

class SampleTimeProvider : TimeProviderManager.ITimeProvider {
    override fun getCurrentTime() : Long {
        // Get the current time in milliseconds.
        return System.currentTimeMillis()
    }
}
startcode// During initialization of your app
if (TutorialAppPlus.useCustomTimeProvider) {
    TimeProviderManager.setInstance(SampleTimeProvider())
}

Working example in Tutorial App

  • Refer to SampleTimeProvider.kt

Sign-up

To streamline the user's experience when signing up with your app, the SDK can display a button that starts the sign-up process directly from the sign-in page.

When the user clicks Sign Up, the App SDK collects specific information from the user.

To take advantage of this feature, your application must:

  1. Call the AdaptiveUI.getAuthenticationFragment() with the signUpOpts parameter. Specify the information you want to collect from the user inside the signUpOpts parameter.

val signUpOpts = HashMap<String, String>()
signUpOpts[EXTRA_KEY_SIGN_UP_ENABLED] = "true"
signUpOpts[EXTRA_KEY_SIGN_UP_FULL_NAME] = "required"
signUpOpts[EXTRA_KEY_USER_NAME] = "required"
signUpOpts[EXTRA_KEY_SIGN_UP_EMAIL_ADDRESS] = "required"
signUpOpts[EXTRA_KEY_SIGN_UP_PHONE_NUMBER] = "optional"
signUpOpts[EXTRA_KEY_SIGN_UP_FIDO] = "true"
signUpOpts[EXTRA_KEY_SIGN_UP_PHOTO_ID] = "true"
val fragment = AdaptiveUI(Config).getAuthenticationFragment(null, null,authOpts, suggestRegOpts, signUpOpts)

For a detailed description of signUpOpts, refer to AdaptiveUI.getAuthenticationFragment() in the Client API Docs.

  1. Implement the ISignUpProcessorAsync interface by defining the two functions: startSignUp() and finishSignUp().

The startSignUp() function:

  1. calls your application server to start account creation

  2. creates a sessionData object with a JWT sessionKey that contains a custom sign_up claim in the payload, and

  3. returns a SignUpSession object containing the userName and the sessionData.

The finishSignUp() function:

  1. calls your application server to finish the account creation. Your application server returns the userName and sessionData to your Android application to sign the user in, and

  2. returns a SignUpSession object that contains the userName and an updated sessionData object without the sign_up claim.

In case of an error, both startSignUp() and finishSignUp() call SignUpController.onError().
class SignUpProcessor(signUpController, signUpOpts) : ISignUpProcessorAsync {
    override fun startSignUp(
      signUpData: Map<String, String>,
      callback: ICompletionCallback<SignUpSession>
    )
    {
        // Start account creation, choose userName, create sessionData
        // and call the SignUpController.
    }
    override fun finishSignUp(
      signUpSession: SignUpSession,
      callback: ICompletionCallback<SignUpSession>
    )
    {
        // Verify that required methods are registered,
        // update the sessionData and call the SignUpController.
    }
}
  1. Subclass the SignUpProcessorFactory abstract class and define the createSignUpProcessor() method to create an instance of ISignUpProcessor.

class TutorialSignUpProcessorFactory: SignUpProcessorAsyncFactory() {
    override fun createSignUpProcessor(signUpController, signUpOpts) 
                                                        : ISignUpProcessorAsync {
        // Create and return a SampleSignUpProcessor instance.
        return SignUpProcessor(controller, signUpOpts)
    }
}
  1. Set the SignUpProcessorFactory class in the AppSdk by calling SignUpProcessorFactory.setInstance().

SignUpProcessorAsyncFactory.setInstance(TutorialSignUpProcessorFactory());

For more details on these interfaces, refer to the corresponding sections in the Client API Docs.

Working example in Tutorial Web App

  • Refer to TutorialSignUpProcessorFactory, SignUpProcessor, TutorialAppPlus and MainActivity classes.

Transaction

In the S3 Suite, transactions are cryptographic proof of a user's consent to a specific set of transaction details, such as purchasing merchandise totalling $385 or transferring $5,000 from the user's checking account to their money market account. The Authentication Server must be configured to support transactions, refer to Configure Transactions.

In order to simplify integration with your application, the Nok Nok App SDK implements the transaction flow for you. Your app sets the authentication options and calls AdaptiveUI.transactAsync(). The SDK interacts with both the user and the Authentication Server to either successfully complete the transaction or report that authenticating the transaction is not possible. You can create a custom UI for Transaction, see Replace the Transaction UI.

Before starting the transaction process, your application generates a transaction ID and formulates the transaction text based on user inputs.

Then when your app calls AdaptiveUI.transactAsync(), the App SDK shows the transaction confirmation screen with transaction details and checks if there is an authentication sequence that only contains a single authenticator. If so, it verifies the user's identity with that authenticator. If not, then it displays a list of available authentication methods on the modal dialog.

In the successful case, AdaptiveUI.transactAsync() returns an AdaptiveResult object containing all the necessary information about the completion of the operation. In the case of failure, AdaptiveUI.transactAsync() returns an exception containing all the necessary information about the error.

The following code performs the whole transaction flow. A description of each step follows.

// Step 1: Create a HashMap for extras and insert the key-value pair for the
// confirmation text.
val extras: HashMap<String, String> = HashMap()
extras[EXTRA_KEY_OPTIONS] = String.format(Locale.getDefault(),
     "{\"%s\": \"Authorize $%d payment?\"}",
     IAppSDKPlus.EXTRA_KEY_OPTION_TRANSACTION_TEXT, transactionAmount)
// Step 2: Trigger the transaction
AdaptiveUI(TutorialAppPlus.authType.appSdkPlusConfig).transactAsync(
     activityProxy,
     transactionId,
     sessionData,
     extras,
     { result, error ->
           if (error != null) {
                 // Step 3: Show an error using LiveData in the completion callback
                 mResultMessage?.postValue(MessageShowInfo(
                      java.lang.String.format( "%s%s",
                             error.resultType.getMessage(TutorialAppPlus.app),
                             TutorialAppPlus.getGeneratedMessage(e))))
           } else {
                 // Step 4: Show an operation completion message using LiveData in the completion callback
                 mResultMessage?.postValue(MessageShowInfo(
                      TutorialAppPlus.app.getString(R.string.transaction_complete
                      )))
           }
     }
)
  1. The App SDK can show details of the transaction that are contained in a HashMap. These details include transaction text, transaction ID and additional information like when you are sending signals and passing in context data needed by your Authentication Rules.

If you want to trigger the Quick Authentication feature, also use extras to indicate your preferred Quick Mode. For more information, see Implementing Quick Authentication.

  1. Trigger the transaction for the user by calling AdaptiveUI.transactAsync().

  2. If the user successfully authenticates the transaction, the transactAsync() method provides the result parameter to the callback which is an AdaptiveResult object containing the result of the authentication operation. mResultMessage is a LiveData object.

  3. If authentication fails, the transactAsync() method provides an error to the callback which is an AppSDKException with a result that contains information about the issue. mResultMessage is a LiveData object.

  • The call to AdaptiveUI.transactAsync() first tries to do the transaction using AutoStart.AUTO_ANY mode. Then if the user cancels an authentication method or user interaction is needed, AdaptiveUI.transactAsync() calls fragment.showModal() and switches to AutoStart.AUTO_NONE mode.

  • You can specify a different AutoStart mode in the extras parameter. Use EXTRA_KEY_AUTO_START as the key and the desired mode as its value, for example:
    extras[EXTRA_KEY_AUTO_START] = AUTO_FIDO

  • If you want AdaptiveUI.transactAsync() to behave the same way as AuthenticationController.enable(AutoStart.AUTO_FIDO), define a new authentication rule in the Authentication Server customized for transaction that has a single sequence containing only the FIDO Auth method.

For more information on the AdaptiveUI and AdaptiveResult classes and methods, see the Client API Docs.

Working examples in Tutorial App

  • Refer to TransactionFragment.kt to see a sample transaction initiation UI.

Implementing Quick Authentication

When using Transaction flow, you can eliminate the initial interaction with the Authentication Server by Registering for Quick Authentication and then implementing it when authenticating the transaction. After Quick Authentication, if the server requires additional authentications to be performed then the SDK prompts the user to perform those additional authentications.

Perform Quick Authentication for a transaction by first retrieving the quickData object from UserDataCache as shown in the code snippet below. The username is a required parameter. If you assign a name to the QuickData object, then pass it to getQuickAuthData() as the second parameter, otherwise pass in null.

// Retrieve the QuickData object using the default name
val quickData = UserDataCache.getInstance(TutorialAppPlus.app)
.getQuickAuthData(username, null)

Then pass quickData in extras to AdaptiveUI.transact(), using the key EXTRA_KEY_QUICK_DATA.

val extras: HashMap<String, String> = HashMap()
extras[IAppSDKPlus.EXTRA_KEY_QUICK_DATA] = quickData
AdaptiveUI(TutorialAppPlus.authType.appSdkPlusConfig).transactAsync(
    activityProxy, 
    transactionId,
    sessionData,
    extras,
    completionCallback)

Working example in Tutorial App

  • The Transaction feature in the Tutorial App doesn't use Quick Authentication, but refer to ExtrasHelper.kt for an example of how to set extras.

Specifying which authenticators to trigger

The SDK allows your app to specify which authentication methods to trigger automatically during the authentication flow. For example, you may want to always trigger a registered FIDO authentication method or never trigger a password authenticator. Do this by setting an autoTriggering mode for each authentication method.

autoTriggering Mode

Description

NO_CHOICE

Automatically trigger this authentication method if the user has no other choice. This is the default.

ALWAYS

Always trigger the method if it is present

NEVER

Never trigger the method automatically.

Create an object of class MethodBehavior for each authentication method. Set the autoTriggering mode inside each object. Place these objects into an array of MethodBehavior objects. Finally, pass the array to your AuthenticationController object.

val externalBehavior = MethodBehavior(EXTERNAL_AUTH_TYPE, EXTERNAL_AUTH_NAME, AutoTrigger.NEVER)
val fidoBehavior = MethodBehavior(FIDO_AUTH_TYPE, FIDO_AUTH_NAME, AutoTrigger.ALWAYS)
val behaviors = ArrayList<MethodBehavior>()
behaviors.add(externalBehavior)
behaviors.add(fidoBehavior)
mAuthController.setMethodBehavior(behaviors)

For more information on the MethodBehavior and AuthenticationController classes, see the Client API Docs.

Working example in Tutorial App

  • Refer to SampleAdaptiveAuthFragment.kt

Sending signals and passing in context data

If you define Authentication Rules or Registration Decision Rules that use signals and context data, you need to ensure that this data is sent to the Authentication Server so it can use this information. The App SDK automatically sends simpler signals, like the device model and manufacturer, to the Auth Server. User location and WiFi network take more resources and time to process, so you must configure the App SDK to generate and send these signals. See Configuring Signal Generation under The Client Configuration File.

To pass context data like transaction amount and transaction type to getAuthenticationFragment(), use the authOpts parameter to that method. authOpts is a hashmap of key-value pairs, so you can pass in an arbitrary amount of data.

Create a JSON object that contains a name-value for each piece of information you plan to send as context data. This name must match what your Adaptive Rules use. You can create a hashmap and insert a key-value pair for your context data. If you have a rule whose condition uses location and the is with in provided location operator, you must include a context data entry for providedLocation, as shown below.

Identify the JSON object containing all your context data by using the key IAppSDKPlus.EXTRA_KEY_CONTEXT_DATA. Pass the hashmap to getAuthenticationFragment().

private HashMap<String, String> authOpts;
// Create the Context data JSON for the transaction amount and type
final JsonObject contextData = new JsonObject(); contextData.addProperty("transactionAmount", "300"); 
contextData.addProperty("transactionType", "purchase");
contextData.addProperty("providedLocation", "{\"status\":0,\"latitude\":32.52,\"longitude\":-124.482,\"accuracy\":99.2,\"countryCode\":\"US\"}");
// Identify the data as context data by using the EXTRA_KEY_CONTEXT_DATA key.
authOpts.put(EXTRA_KEY_CONTEXT_DATA, contextData.toString());

Managing registrations

Your app can provide a way for users to view, rename and deregister their registered FIDO authenticators across different devices. Call the manageRegistrations() method in class AppSDKPlus, which returns the fragment shown below. Add the fragment into your app to show the user both UAF and FIDO2 authenticators. This fragment is independent of the protocol you specified when you created the AppSDKPlus object. By interacting with this fragment, the user can view, rename, or deregister FIDO authenticators.

Some authenticators support device-bound keys called DPKs. A row for this type of authenticator is expandable to list all of the DPKs it supports. Each DPK may be renamed or deregistered separately.

After creating the AppSDKPlus object, get the session object that was created during sign in, see SessionData. Next, create the fragment by calling manageRegistrations().

Fragment tokenDeregistrationFragment = appSDKPlus.manageRegistrations(
                   appContext, sessionData, HashMap<String, String> extras);

From the UI thread, insert the fragment into your page. If you want to offer the ability to manage non-FIDO authentication methods, use the fragment for registering other (non-FIDO) authentication methods.

The view above displays a credential icon defined by the FIDO Authenticator Metadata Specification (MDS), along with additional details such as the credential name and the timestamp of its last usage. If the corresponding MDS entry does not include an icon, the default icons provided by Nok Nok are used instead, as shown in the screenshot above. To enable the display of MDS icons, add the “needDetails” data and set it to 4 in extras before calling manageRegistrations().

extras[IAppSDKPlus.EXTRA_KEY_OPTIONS] = "{\"needDetails\": 4}"

If your app is unable to establish a network connection with the Server, you can force offline deletion of all local UAF registrations associated with its appID. Use AppSDKPlus.clearLocalRegistrations() and pass in the appID.

clearLocalRegistrations() deletes registrations for all the users on the device for the respective appID. The appID is configured on the Server as uaf.application.id and it is sent to the client during registration.

Suspend registration

To give users the ability to suspend a registered FIDO credential without removing it, set the suspendRegistrationEnabled flag to true in the client configuration file. The ManageRegistrationsFragment then looks like the one below.

Note that the Remove button is now labeled Deactivate. If the user clicks the Deactivate button, the App SDK displays the following dialog:

The end user can re-enable a suspended registration by clicking the Enable button.

Working example in Tutorial App

  • Refer to file SampleManageFragment.kt.

Session refresh

If your application refreshes the sessionData token, it needs to provide the new session token to the App SDK so the App SDK can pass it to all active controllers. Below is an example of an application passing renewed session data to the App SDK.

OperationResultListener.getInstance(context).onSessionDataUpdated(newSessionData)

The Tutorial App contains a sample implementation of session renewing logic based on user activity detection and session expiration.

Working examples in Tutorial App

  • Refer to SessionManager.kt for a session renew handler.

  • Refer to MainActivity.kt for a session manager usage.

Out-of-band authentication

Securely authenticating users who are using a web app from your company can be challenging. You don't know if the user is the actual person or someone who has stolen your user's login credentials. Many desktop computers and laptops can't authenticate a user because they don't have a built-in fingerprint scanner or a hardware key store, like a TPM chip.

Out-of-band (OOB) authentication enables you to use a second device tied to the user, typically their cell phone, to authenticate. Your web app initiates authentication by either

  • Sending a push notification to your mobile app installed on the user's cell phone. When the user receives the notification, they authenticate with your mobile app using a registered FIDO authenticator, like fingerprint.

  • Displaying a QR code on the device running your web app. The user scans the QR code with their second device using either your mobile app or the camera app. For more information, see Processing QR Codes Using the Camera App. Then the user authenticates with a registered FIDO authenticator on their second device.

While a push notification can start authentication for a user, it cannot be used to trigger registration for an authenticator. Scanning a QR can initiate both registration and authentication.

The App SDK supports OOB in devices using either Google Play Services or Huawei Mobile Services (HMS). You can implement your app to support both these services or just one of them.

OOB requires configuring your app on the Authentication Server and, if you use push notifications, it requires using Firebase Cloud Messaging (FCM) or Huawei Mobile Services (HMS). See Out-of-band.

Implementation overview

To respond to push notifications in your app:

  1. If you are using FCM, add Firebase configuration to your Android project. For more information, see Adding Firebase Configuration. If you are using HMS, see Adding Huawei Mobile Services configuration.

  2. See Editing the Manifest file to include FCM and/or HMS services for push notifications.

  3. Initialize for OOB. For more information, see Initializing for Out-of-band Authentication.

Your web app can send a push notification for OOB authentication after OOB registration, without requiring that the user be authenticated with QR-code OOB authentication first.

To implement QR code scanning in your app:

  1. Initialize for OOB. For more information, see Initializing for Out-of-band Authentication.

  2. Create the QR Code Scanner. For more information, see Creating the QR Code Scanner.

To control the type of QR code that is displayed during registration or authentication, see Specifying the QR Code Type to Display.

See Replacing the OOB Method UI for ways you can tailor OOB authentication.

Adding Firebase configuration

Enable push notification support by updating your resources file and secure your app by restricting its API key to work with the Firebase API. The instructions assume that Firebase has been added to your app.

Update your resources file

To configure your Android app for Firebase so it responds to push notifications, add the following 3 strings to strings.xml.

  • google_app_id

  • google_api_key

  • project_id

Find the values to use in your Firebase project's google-services.json file. Your strings.xml entries are similar to what's shown below.

<string name="google_app_id" 
    translatable="false">1:123928937488:android:2c5157c8cb1300ad</string>
<string name="google_api_key" 
    translatable="false">AIzaSyB0MHZW7dgyC4bXZSaV0GcFRE5bJlvYOf0</string>
<string name="project_id" translatable="false">push-2a5ff</string>

Restrict your app's Google API key

Secure your app's Google API key by restricting it to use only with the Google Play Integrity API and the Firebase Installations API. Use Google's Cloud Console to edit your API key, as shown below. See Apply API Key Restrictions for more information.

Adding Huawei Mobile Services configuration

Enable push notification support by adding the HMS Push Kit and secure your app by restricting its API key to work with the Push Kit.

For push notification to work, configure your app in Huawei's AppGallery Connect. See Configure your app information in AppGallery Connect. Follow the steps below.

  1. Enable the Push Kit and configure the SHA-256 certificate fingerprint.

  2. Download the configuration file agconnect-services.json and put in your project. See section Integrating the AppGallery Connect SDK in Android Studio in Huawei's Getting Started with Android.

Restricting your app's HMS API key

To secure devices using HMS, restrict your API key to only use push notification. Go to HMS API Services > Credentials and choose your project.

Click the API key's Edit button. The following Edit Key Restrictions dialog appears. At the bottom, under the API restrictions section, select Restrict this Key. Add Push Kit.

For more details on the API Console, see Huawei's API Console Operation Guide.

Editing the manifest

Add the appropriate services to the mobile application’s manifest file for push notifications:

<!--  Service declaration for FCM push notification -->
<service
        android:name="com.noknok.android.client.appsdk.fcmpush.FCMMessageHandler">
        android:exported="true"
        android:permission="com.noknok.permission"
        android:protectionLevel="normal">
        <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
                <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
        </intent-filter>
</service>
<!--  Service declaration for HMS push notification -->
<service
        android:name="com.noknok.android.client.appsdk.hmspush.HMSMessageHandler" > 
        <intent-filter>
                <action android:name="com.huawei.push.action.MESSAGING_EVENT" />
                <action android:name="com.huawei.push.action.INSTANCE_ID_EVENT" />
        </intent-filter> 
</service>
<activity 
        android:name="com.noknok.android.client.oobsdk.OOBHandlerActivity"
        android:exported="true"
        android:permission="com.noknok.permission"
        android:protectionLevel="normal">
               …      
</activity>

Initializing for out-of-band authentication

You must initialize the App SDK before you can use it to process push notifications or QR code scans. Use the following classes:

  • com.noknok.android.client.appsdk.IAppSDK

  • com.noknok.android.client.appsdk.ProtocolType

  • com.noknok.android.client.appsdk.AppSDKFactory

  • com.noknok.android.client.appsdk.AppSDK2

  • com.noknok.android.client.oobsdk.OobReceiver

To initialize for OOB using these classes:

  1. Create an IAppSDK instance.

// Use the UAF protocol.
iAppSDK = AppSDKFactory.createInstance(ProtocolType.UAF);
  1. Create an OobReceiver instance, this is the main class containing OOB functionality.

// This class contains functions to process OOB operations 
// for QR code and push notifications.
OobReceiver oobReceiver = OobReceiver.instance();
  1. Create and initialize an AppSDK2 instance using the IAppSDK instance you created. This class interacts with the Authentication Server to perform FIDO operations.

oobReceiver.setAppSDK2(new AppSDK2(getApplicationContext())
                .addAppSDK(iAppSDK));
  1. Assign the URLs for the registration and authentication endpoints. Do this if your mobile app performs OOB registration and OOB authentication for a specific web app. The App SDK uses these endpoints and ignores the URL in the QR Code.

    If you implement a mobile app, similar to Nok Nok Passport, that performs OOB registration and authentication for several web apps, then skip this step. In this situation, the mobile app must use the URL from the QR Code.

oobReceiver.setURLs(reg_url, auth_url);

Working example in Tutorial App

  • Refer to onCreate() in file TutorialAppPlus.java.

Creating the QR code scanner

The App SDK includes classes that provide full support for QR code scanning. These classes interact with the camera to extract information from the QR Code and communicate with the Authentication Server to perform the requested FIDO operation.

To use QR Code scanning in your app, import the following classes:

  • Google and Huawei:
    com.noknok.android.client.oobsdk.ScannerFragmentHelper

  • Google only:
    com.noknok.android.client.oobsdk.vision.ScanQRFragment

  • Huawei only:
    com.noknok.android.client.appsdk.hmsscan.ScanQRFragment

ScannerFragmentHelper dynamically detects supported Mobile Services and added libraries. It instantiates the correct version of the scanner fragment with the following call:

Fragment scannerFragment = 
    ScannerFragmentHelper.getScannerFragment(context, null);

If your app is missing a QR-scanning library or is using the wrong one, an AppSDKException with result type INVALID_STATE is thrown on scanner initialization.

Working example in Tutorial App

  • Refer to file ScanCodeFragment.kt.

Sending custom push notifications

You can use FIDO Out-of-Band to authenticate a user during login, and also when a user confirms a transaction. In either case, your app can dynamically specify the text that the App SDK sends to the user in the push notification.

Authentication during login

By default, the Server sends the same configurable, static push notification authentication text to every user when they authenticate with a push notification. You can include the user name and other information specific to the user by customizing that text for each user. This requires a change to both the Server configuration and your client app.

  1. Use the Server's Admin Console to change the Push Notification Authentication Text Mode to Dynamic. Login to the Admin Console, select the desired tenant and navigate to Configuration > Authentication Methods > Out-of-band. Update Push Notification Authentication Text Mode. For more information, see Step 4. in Out-of-band.

  2. Set the custom push notification text dynamically in the extras parameter in your client application before calling getAuthenticationFragment().

extras[IAppSDKPlus.EXTRA_KEY_AUTH_NOTIFICATION_TEXT] = "Custom push text";

Transaction confirmation

By default, the Server sends the same configurable, static Push Notification Transaction Text to every user when they confirm a transaction with a push notification. You can include the user name and other information specific to the user by customizing that text for each user. This requires a change to both the Server configuration and your client app.

  1. Use the Server's Admin Console to change the Push Notification Transaction Text Mode to Dynamic. Login to the Admin Console, select the desired tenant and navigate to Configuration > Authentication Methods > Out-of-band. Update Push Notification Transaction Text Mode. For more information, see Step 4. in Out-of-band.

  2. Before calling AdaptiveUI.transact() from your client application, dynamically set the push notification transaction text as the value for the key IAppSDKPlus.EXTRA_KEY_OPTION_TRANSACTION_TEXT in the extras parameter. For more information, see Transaction.

Pending authentications

In some cases, a push notification that your application sends to a secondary device does not arrive there. Here are some of the reasons that the push notification can end up in a pending state:

  • the user might have turned off push notifications for the app on their secondary device

  • the push notification service has technical difficulties

  • the user might make several purchases quickly.

To address these situations, the App SDK provides a method that allows your application to list all pending out-of-band authentications. The user can then view this list of pending authentications and choose which one they want to approve or reject.

To take advantage of this feature:

  1. By default this feature is turned off and it requires a configuration change on the Server to enable it. Use the Command Line Interface to the Server to set the System property oob.list.auth.enabled to true.

./nnl-mgmt.sh properties set -name oob.list.auth.enabled -value true
-tenantid SYSTEM

Restart Tomcat.

  1. In your app, create the AppSDKPlus object and get the sessionData object that was created during sign in.

  2. Call getPendingAuthsFragment() and receive the instance of BasePendingAuthsFragment in return.

  3. Show the BasePendingAuthsFragment so the user can interact with it.

// 2) Create an AppSDKPlus instance.
val appSDKPlus = AppSDKPlus(AppSdkPlusConfig, Context)
// 3) Get PendingAuths fragment.
val fragment = appSDKPlus.getPendingAuthsFragment(Context, SessionData, null)
// 4) Show PendingAuths fragment.
supportFragmentManager.beginTransaction()
                .replace(R.id.content_frame, fragment).commit()

The method getPendingAuthsFragment() returns a fragment that contains the authentications that are pending on all devices. If you want the pending authentications for the current device only, set the flag currentDeviceOnly to "true" inside extras, and pass extras to getPendingAuthsFragment().

// Create extras
val extras: HashMap<String, String> = HashMap()
extras["currentDeviceOnly"] = "true"
// Get PendingAuths fragment.
val fragment = appSDKPlus.getPendingAuthsFragment(Context, SessionData, extras)

Working example in Tutorial App

  • Refer to file MainActivity.kt.

Specifying the QR Code type to display

Unless your app has implemented push notifications, your app automatically displays a QR code if the user registers a FIDO OOB authenticator or uses FIDO OOB to authenticate. By default, the QR code type generated for registration and authentication is APP_ANY_RP which means it can be scanned by native mobile apps and Nok Nok's Passport app. Your particular situation may require a different QR code type depending on the apps that need to scan it.

The table below describes the types of QR codes and what kind of apps can successfully scan it to either register or authenticate. The QR code types are ordered by the size of the QR code they generate, from largest to smallest. Larger QR codes can be scanned by a greater variety of apps but it's best to select the smallest QR code type for your situation.

QR Code Type

Description

UNIVERSAL_ANY_RP

Generates a universal QR code that can be scanned successfully by mobile apps, web apps, and camera apps that can process QR codes. These apps can be deployed by different organizations.

UNIVERSAL_RP_SPECIFIC

Generates a universal QR Code specific to apps deployed by one organization. The API Server hostname is omitted from the QR code.

APP_ANY_RP

The default QR code type. Generates a QR Code that works with native mobile apps deployed by different organizations. The web page hostname is omitted from the QR code.

APP_RP_SPECIFIC

Generates a QR code that can only be scanned by native mobile apps deployed by one organization. The Auth Server omits both the web page and API Server hostname from the QR code.

Mobile apps that scan this QR code must hard code the registration and authentication endpoints as described in Step 4 in Initializing for Out-of-band Authentication.

Pass in the QR code type to an App SDK method using the extras parameter. You also need to pass in the web page URL using extras if the QR code type is either UNIVERSAL_ANY_RP or UNIVERSAL_RP_SPECIFIC. The web page URL handles either OOB registration or OOB authentication depending on whether the App SDK method you call registers or authenticates.

This example shows how to pass QR code type UNIVERSAL_ANY_RP and a web page URL to adaptiveUI.getAuthenticationFragment(). If the user decides to use FIDO OOB to verify their identity, the Authentication Server generates a QR code that can be scanned by any native mobile app.

val extras = HashMap<String, String>();
extras[IAppSDKPlus.EXTRA_KEY_QR_TYPE] =
    AppSDKPlus.QRType.UNIVERSAL_ANY_RP.name;
extras[IAppSDKPlus.EXTRA_KEY_QR_WEB_URL] = 
    "https://example.com/mywebapp/oobAuth.html";
val fragment = adaptiveUI.getAuthenticationFragment(sessionData,
                           null, extras);

You can pass in the QR code type, and web URL if needed, to any App SDK methods that register or authenticate using FIDO OOB. You can also pass in this information to methods used for device blessing support. The QR code types are defined on the AppSDKPlus.QRType class in the Client API Docs.

Passing data between devices

In some cases you may need to pass data, such as an access token, from the first OOB device to the second. Place the data into the oobRefId on the first device and it will be included in the OOB data received on the second device.

To send the oobRefId from the first device:

// Encode data as Base64
val oobRefId = Base64.encodeToString(data_to_be_shared,
   Base64.URL_SAFE or Base64.NO_PADDING or Base64.NO_WRAP)
// Put in the extras
extras!![IAppSDKPlus.EXTRA_KEY_OOBREFID] = oobRefId
adaptiveUi.registerQrAsync(sessionData, callerActivityProxy, extras, completionCallback)

To receive the oobRefId in the second device:

//set a custom OOB completion listener
mOobReceiver.setCompletionListener({ callerActivityProxy: ActivityProxy, resultType:ResultType, refId:String?, operation:AppSDK2.Operation?  ->
   Log.i(TAG, "CompletionListener: $operation, refId: $refId, status: $resultType")
})

Working examples in Tutorial App

  • To send the oobRefId, refer to file RegControllerFragment.kt

  • To receive the oobRefId, refer to file TutorialAppPlus.kt

Processing QR codes using the camera app

Your mobile app can authenticate a user that is running a web application on a desktop browser. The web application can display a QR code and the mobile device's Camera app can scan the QR code. If your app is installed on the mobile device, the Camera then automatically opens your mobile app to process the QR code. If your app is not installed on the mobile device, the Camera app automatically opens the mobile device's browser to a webpage that can process the QR code.

To use this feature, your mobile app needs to know the URL of the web application that may use your app to help authenticate its users. In the AndroidManifest.xml file for your mobile app, add the URL of the web app into the <data> element inside the <intent-filter> element inside the <activity> element for the OOBHandlerActivity. In the example below, the server host used is "evaluation93.noknoktest.com".

<activity android:name="com.noknok.android.client.oobsdk.OOBHandlerActivity"
   <intent-filter android:autoVerify="true"
       <data android:scheme="https" android:host="evaluation93.noknoktest.com"/>
   </intent-filter>
</activity>

Note that the QR code type displayed by the web application must be a universal QR code.

Working example in Tutorial App

Refer to file:

  • AppSDK/android-studio/app_tutorial_plus/app/src/android/AndroidManifest.xml

Device blessing support

Device blessing is a QR code-based OOB mechanism that enables the user to initiate registration on a new device by using a previously-registered device.

The following steps describe how Tutorial App uses device blessing implemented in AdaptiveUI:

  1. On the previously-registered device, the user taps the Register with QR Code button in the Register tab. Use AdaptiveUI.registerQrAsync(), as shown below, to display the QR code returned by the Server.

AdaptiveUI.registerQrAsync(sessionData, callerActivityProxy, extras, completionCallback)
  1. On the new device, the user selects the Scan Code tab and scans the QR code displayed on the previously registered device.

  2. When registration is completed on the new device, the previously registered device displays the successful confirmation screen.

In the above scenario, the QR code is generated on the previously-registered device. You can also implement device blessing by generating a QR code on the new device. Please see the documentation on AdaptiveUI.authenticateQrAsync() for more information.

By default the QR code type generated by registerQrAsync() is APP_ANY_RP which means it can be scanned by mobile apps and Nok Nok's Passport app. For more information about the different QR code types, see the AppSDKPlus.QRType class in the Client API Docs.

checkRegPossible() or checkAuthPossible() are useful for device blessing. Use them to check if a device has already been activated.

Configuring the FIDO OOB option for your users

To create the best user experience for OOB, the Server keeps track of whether your app supports QR code scanning. If your app does not include the OOB library, the App SDK automatically informs the Server that OOB is not supported. You can also enable or disable QR Code scanning for your app by configuring the Server directly using the Admin Console. The instructions below show how your app can dynamically enable or disable support for QR Code scanning using the App SDK.

The following example informs the Server that this app does not support QR code scanning on the current device.

  1. Create a hashmap object and assign "false" to the key EXTRA_KEY_QR_SUPPORTED.

val extras: HashMap<String, String> = HashMap()
extras[IAppSDKPlus.EXTRA_KEY_QR_SUPPORTED] = "true"
  1. Pass the HashMap object in the extras parameter when you call AppSDKPlus.getRegistrationFragment().

var frag = appSdk.getRegistrationFragment(context, sessionData, extras)
  1. Pass the HashMap object in the authOpts parameter when you call AdaptiveUI.getAuthenticationFragment().

var frag = adaptiveUI.getAuthenticationFragment(sessionData, null, extras)

Using a phone as a roaming authenticator

You can use a phone as a Bluetooth Low Energy (BLE) enabled roaming authenticator for FIDO2. For example, this allows you to sign-in on a FIDO2-enabled desktop browser using a phone. The browser must be running on a Windows computer.

Adding BLE authenticator support

Start by including BLE authenticator functionality in your application. Add the following dependencies to your application’s build.gradle file.

asmsdk_ble
asm_native_fps

By default, the BLE authenticator uses biometric user verification so it requires asm_native_fps.

The BLE authenticator requires Android 6+, which the code below checks. To activate the authenticator, the application starts BLE advertising using the following call.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        BleDispatcher.getInstance(callerActivityProxy).startAdvertising();
}

To deactivate the BLE authenticator, perform the following call.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        BleDispatcher.getInstance(callerActivityProxy).stopAdvertising();
}

Call stopAdvertising() before the activity closes.

Using the BLE authenticator

In order to use your phone as a roaming authenticator, you pair it with a Windows computer using Bluetooth pairing. Next, you can register the authenticator, then use it to sign in.

Pairing

To pair your phone with a Windows computer, start advertising mode on your application. Use the following instructions.

Open Settings. Go to Devices > Bluetooth & other devices. Click Add Bluetooth or other device.

The Add a device dialog appears. Click Bluetooth.

The Add a device dialog's appearance changes. Click on your phone's model.

The dialog displays a PIN. Input this PIN on your phone.

After pairing completes, the dialog displays a completion message. Click Done.

After pairing completes, the dialog displays a completion message. Click Done.

After pairing, you can register the BLE authenticator on FIDO2-enabled website.

Registering

To register, your app must start BLE advertising. Then follow these instructions on a Windows computer:

Using a FIDO2-enabled desktop browser, open Tutorial Web App at the following URL: https://evaluation93.noknoktest.com:8443/gwtutorial/

If this is the first time you are using Tutorial Web App, enter a unique login name and use noknok as the password. After you successfully login, the Register page appears.

To register a Bluetooth security key, go to the second row and click the plus sign. If you set up a PIN on your computer, you may be prompted to enter it. If so, you should click Cancel. This dialog appears:

After clicking OK, this dialog appears. Click OK on this dialog.

After a few seconds, this dialog appears.

On your mobile device, you are prompted to scan your fingerprint to complete registering your BLE authenticator. The successful completion message is shown after your BLE authenticator has been registered.

The registered BLE authenticator is visible on the Manage page as shown below

Authenticating

To authenticate, your app must start BLE advertising. Then follow these steps on a Windows computer.

Using a desktop browser, open Tutorial Web App at the following URL: https://evaluation93.noknoktest.com:8443/gwtutorial/

Enter the username who registered the BLE authenticator and click Next. This dialog appears.

After a few seconds, this dialog appears.

On your mobile device, you are prompted to scan your fingerprint to complete authentication. After you scan your fingerprint, you are signed in.

Embedding a WebView

The App SDK allows you to embed a WebView component in your app. Use this to render part of your app's UI using HTML, or to load into your app an entire web application that was developed with the NokNok Web App SDK. The WebView can trigger FIDO2, UAF, and OOB operations. The Android App SDK classes WebAppSDK and WebOobSDK support this feature.

To initialize an object of class WebAppSDK, you need:

  • an AppSDK2 object

  • a WebView object that already contains:

    • an initialized Web interface

    • a load URL

    • a WebViewClient implementation

webAppSDK = WebAppSDK(null, AppSDK2)
webAppSDK.init(ActivityProxy, webview, LifecycleOwner)

If you want OOB functionality, you need to also perform these additional steps:

webOobSDK = WebOobSDK()
webOobSDK.init(context, webview)

Next, override the onPageFinished() function in WebViewClient and include a call to the onPageFinished() function of both App SDKs. Note that the second call to webOobSDK.onPageFinished() is only needed for OOB functionality:

override fun onPageFinished(view: WebView, url: String) {
    super.onPageFinished(view, url)
    webAppSDK.onPageFinished(view, url)
    webOobSDK.onPageFinished(view, url)  // Only needed for OOB functionality
}

Your app can now call the Kotlin or Java method WebView.loadUrl() to load the desired HTML.

Working example in Tutorial App

  • Refer to file WebViewFragment.kt for an example of WebAppSDK initialization

Controlling authenticator selection

When you configured the Nok Nok Authentication Server, you defined FIDO policies that enforce your organization's choice of valid UAF and/or FIDO2 authenticators for registration and authentication. Additionally, you can choose to filter out authenticators before they're shown to the user. You can achieve this by customizing the filter chain.

During authentication, the App SDK displays a screen to allow the end user to pick an authenticator. During registration, the App SDK displays a list of available authenticators that you can register. You can programmatically change the UI by customizing the filter chain.

Tutorial App contains an example of how to do this. This example sets SampleAuthenticatorFilterChainFactory. This sample chain consists of the filters shown below. The first 6 are filters used by the DefaultAuthenticatorFilterChainFactory.

The last filter in the chain is either the default UIAuthenticatorFilter or a custom filter that you implement. SampleAuthenticatorFilter is an example of such a custom filter.

  1. DuplicateAuthenticatorFilter: Removes duplicate authenticators.

  2. TitleBasedAuthenticatorFilter: Removes authenticators with the same title.

  3. DisallowedAuthenticatorFilter: Removes authenticators disallowed by a FIDO policy. This filter provides correct policy processing.

  4. CriteriaAuthenticatorFilter: Removes authenticators based on factors like authenticator modality, e.g., fingerprint or AAID. Pass in a special extension during processing to provide filtration criteria.

  5. RetryAuthenticatorFilter: Enables the retry-on-cancel feature. It is used in conjunction with the SelectAndRemember filter to change the remembered selection by canceling and retrying authentication.

  6. SelectAndRemember: Enables the App SDK to remember the user-selected authenticator and use it for subsequent authentications.

  7. At the end of the filter chain you can add a custom filter to replace UIAuthenticatorFilter.

In Tutorial App, SampleAuthenticatorFilter is an example of how to implement a custom filter. It takes an index of the authenticator to select from a list and returns the selected authenticator in the resulting list. It displays a UI to the user to confirm selection. This filter demonstrates how to get parameters into custom filters and perform UI interaction during filtration.

The filter chain factory produces a list of authenticator filters which are each processed in the order that they were added. Each filter is applied on the result of the previous one.

The custom AuthenticatorFilterChainFactory can add any number of existing or new custom filters.

To use standard filters included in the App SDK, your CustomFilterChainFactory implementation should extend DefaultAuthenticatorFilterChainFactory and use special helper methods to add any needed filters. The example below calls the helper method call for DisallowedAuthenticatorFilter.

addDisallowedAuthenticatorFilterAuth(filters, filterParams)

To test this functionality, set the following value to true in the TutorialAppPlus class.

static final boolean replaceAuthenticationFilter = true

The following code replaces the factory class with a custom factory:

AuthenticatorFilterChainFactory.setInstance(SampleAuthenticatorFilterChainFactory())

Working examples in Tutorial App

  • Refer to file SampleAuthenticatorFilterChainFactory.kt for a filter chain factory implementation.

  • Refer to file SampleAuthenticatorFilter.kt for an authenticator filter implementation.

  • Refer to ExtensionHelper.getExtensionsForAuth() in file ExtensionHelper.kt for sample of extension creation for modality-based filtering

See the Client API Docs for more information on the specific APIs.

Managing Personally Identifiable Information (PII)

With the advent of regulatory requirements protecting customers' private data, your apps must enable users to view and delete their sensitive data. The App SDK provides 2 methods you can use: fetchUserDataAsync() and purgeUserDataAsync(). Prior to calling these methods, create an AppSDKPlus object as described in Creating the Main Objects.

The fetchUserDataAsync() method retrieves the user's active and deleted FIDO authenticators as well as non-FIDO authentication methods. Pass in the SessionData, as shown below. SessionData contains the user name.

// Fetching user data from server
appSDKPlus.fetchUserDataAsync(sessionData){ result, error ->
    if (error != null) {
        // creating message for error
    } else {
        // process the result string
    }
}

The result string is a JSON containing a list of Registration JSONs and a list of Method JSONs in string format, as shown below. For the fields contained in Registration and Method, see the Nok Nok Data Types Used by the App SDKs Tech Note.

{
   "statusCode":4000,
   "registrations":[
      {
         "device":{
            "id":"TXF3mo8aJpPrx3_3cWY1_GIvVDqq8YgRfpTWU-tM8jQ",
            "deviceType":"android",
            "info":"Google",
            "model":"Android+SDK+built+for+x86",
            "os":"android 10",
            "manufacturer":"Google"
         },
         "app":{
            "id":"android:apk-key-hash:SvYZ4Sgas9T2+6DpNj566iscuns",
            "name":"android:com.noknok.android.tutorialappplus"
         },
         "authenticators":[
            {
               "description":"Android Biometric",
               "createdTimeStamp":1603692776868,
               "handle":"WyJ1YWZfMS4wIiwiNGU0ZSM0MGFkIiwiVE82NDVlYkp0dlM2cG5XUHJEV3VHeFI0emY3V2NwUFZCdldSd0djVFNaQSJd",
               "status":1,
               "statusDesc":"ACTIVE",
               "lastUsedTimeStamp":1603692776861,
               "authCount":0,
               "protocolFamily":"UAF"
            }
         ]
      }
   ],
   "methods":[
      {
         "type":"Email OTP",
         "name":"OTP Using Email",
         "state":"SUCCEEDED",
         "data":{
            "identifier":"sampleuser@noknok.com"
         }
      }
   ],
   "additionalInfo":{}
}

The purgeUserDataAsync() method hard deletes the user's FIDO authenticators, non-FIDO authentication methods, registration history, authentication history, deregistration history, and history of internal API operations. To delete user data, pass in the sessionData, as shown below. sessionData contains the user name.

// Purging user data from server
appSDKPlus.purgeUserDataAsync(sessionData){ result, error ->
    if (error != null) {
        // creating message for error
    } else {
        //success
    }
}

The result string is a tally of deleted objects. The following is a sample.

{
    "statusCode":4000,
    "additionalInfo":{},
    "stats":{
        "deletedAuthenticatorCount":1,
        "deletedDeviceCount":1,
        "deletedHistoricalDataCount":2,
        "deletedUserOperationsDataCount":1,
        "deletedIdentityMethods":1
    }
}

Working examples in Tutorial App

  • Refer to file MiscellaneousFragment.kt and RegControllerFragment.kt for examples.

Using an External Authentication method

An External Authentication Method allows your users to authenticate with passwords and any other authentication method not currently supported by Nok Nok. In addition, you can include External Authentication Methods in an Adaptive Ruleset. When you trigger an External Authentication Method, an external entity attempts the authentication and provides an acceptable result. This section refers to this external entity as the RP Server. The RP Server is responsible for registering an end user's External Authentication Method.

To use an External Authentication Method, define a new custom class to perform the external authentication, define a new factory class, override createMethodUI() in your factory class, and configure the API Server. Here are the details:

  1. Define a custom class that implements the IExternalAuthLiveData interface. This class presents the UI if needed and asks the user for verification data, creates a credential and sends the credential in the ExternalAuthMethodUi object to process through the processCredential() method. Nok Nok supports two ways to create the credential:

    • JWT External Authentication - Your class calls the RP Server to verify the user. The RP Server returns a JWT as the credential.

    • Password External Authentication - Your class creates an object containing the user's password and passes that object as the credential. The API Server then calls the RP Server to verify the userName and password.

  2. Define a new factory class that is a subclass of MethodUIFactory. For an example, see class SampleMethodUiFactory in Tutorial App Plus. Set an object of your new factory class to be the MethodUIFactory instance.

MethodUIFactory.setInstance(SampleMethodUiFactory())
  1. In your new class SampleMethodUIFactory, override createMethodUI() and other methods. Your factory’s createMethodUI() returns an ExternalAuthMethodUi object. The initialization of ExternalAuthMethodUi requires a LiveData object from the class you implemented in Step 1.

  2. Configure the Server to use your External Authentication Method. See External Authentication Method.

Working examples in Tutorial App

  • For an example implementation of IExternalAuthLiveData, see PasswordAuthUi.kt.

  • For an example definition of createMethodUI(), see SampleMethodUiFactory.kt.

  • For an example of both JWT and Password External Authentication Methods, see the definition of the useJWTExternalAuthentication flag in TutorialAppPlus.kt and its use in PasswordAuthUi.kt.