User interaction typically consists of two steps: the session confirmation and the input of the second factor. Note that, depending on the configuration, the current state of the app and specifics for a given session, the session confirmation or second factor step might be skipped.
After starting a session with startUserInteraction, the Mobile SDK will either trigger a confirmLogin or confirmEnrol callback.
Upon receiving confirmLogin, the app should display a dialog to the user, asking for confirmation. When multiple accounts exist for a server (and no account was pre-selected at the server side), the user should also choose which account it wants to login with.
The server can specify announceInfo for the login, which can contain a logo and an arbitrary set of strings, each identified by a unique key. The app can access this data, by requesting the session's announceInfo.
After confirming and selecting an account, setAccount should be called with the selected account. Optionally, a userInput string can be provided, which can contain arbitrary data to be sent back to the nextAuth server. If userInput was sent, it will be available through the nextAuth Server SDK.
NextAuth.getSessionManager().setAccount(session, account, userInput);
NextAuth.default.setAccount(account, for: session, with: userInput)
account in the
setAccount(session, account) (Android) or
setAccount(account, for: session) (iOS) functions, should be one of the accounts from the list you get back in the ConfirmLogin callback. Do not use the account inside the session (that you also get back in the ConfirmLogin callback), since there will be no account linked to that session prior to this call.
Upon receiving confirmEnrol, the app should display a dialog to the user, asking for confirmation that the user wants to create a new account. When one or more accounts already exist for that server, one can optionally display additional information to the user, warning about existing accounts.
The confirmEnrol callback also contains a visual hash of the server parameters (including the public key), which can be displayed to the user for visual confirmation of the server identity. This can be used as an alternative to public key pinning, when the public key is not known in advance.
When you do not intend to display the visual hash of the server parameters, disabling the visual hash in the configuration will result in a speedup of 100-300 ms.
After the user confirms the creation of a new account, setAccount should be called.
NextAuth.default.setAccount(nil, for: session)
Do not use the
setAccount(session, account) (Android) or
setAccount(account, for: session) (iOS) functions, even if you get a list of accounts back from the Mobile SDK. The list of accounts that you get back in the ConfirmEnrol callback are the accounts that already exist at that server. As you are about to create a new account, you should never set an existing account for this session!
The user is requested to enter a second factor (PIN or biometric). A SecondFactor callback can be received multiple times, for example, if the user fails to input the correct PIN code. There are specific scenarios depending on the already registered second factor.
The SecondFactor callback contains secondFactorInfo, a boolean
stopped, and an optional
session object. If set, the included
session object should be used for displaying additional information to the user.
stopped = true, the nextAuth Mobile SDK has stopped the current user interaction flow, and will no longer listen for sfInput or sfCancel. The app is therefore expected to dismiss the second factor input interface.
Finally, the main information that you will need to build the second factor verification UI is represented by the following properties of the secondFactorInfo object.
The context property of the secondFactorInfo object indicates the action which triggered the second factor interaction:
VERIFY: the user is asked to verify theirself by entering the second factor;
FIRST_SET: the user is asked to set their second factor;
BIOMETRICS_ADD: if the user wants to enable biometrics as a second factor, see Second Factor Management for more details;
BIOMETRICS_REMOVE: if the user wants to disable biometrics as a second factor, see Second Factor Management for more details.
PIN_CHANGE_VERIFY: if the user wants to change their PIN to verify the current PIN or biometric, see Second Factor Management for more details;
PIN_CHANGE_SET: if the user wants to change their PIN to set a new PIN, see Second Factor Management for more details.
You can send either the entered code, biometrics (when possible as indicated
showBiometrics) or both to the Mobile SDK by invoking one of the following methods.
NextAuth.getSecondFactorManager().sfInput(pin); NextAuth.getSecondFactorManager().sfInput(cryptoObject); NextAuth.getSecondFactorManager().sfInput(pin, cryptoObject);
NextAuth.default.sfInput(pin) NextAuth.default.sfInput(info) NextAuth.default.sfInput(pin, and: info)
FIRST_SET or a
PIN_CHANGE_SET, you should ask the user to enter their chosen PIN twice and verify that both match before sending the entered code to the Mobile SDK.
When adding a biometric, the user will be first asked to confirm their biometric through a biometric prompt. On Android, you need to show this biometric prompt on receiving a SecondFactor callback with a BIOMETRICS_ADD context (and showBiometrics = true). On iOS, this is handled from the nextAuth mobile SDK (depending on the OS version, the user will be shown a biometric prompt or not). After confirming their biometric, you will receive (another) SecondFactor callback with a BIOMETRICS_ADD context (and showBiometrics = false), to have the user authenticate their intent of adding biometrics as a second factor.
The secondFactorInfo contains the total number of tries the user has for entering a correct PIN (maxAttempts) and the number of times it tried already (failedAttempts). In case the user used up one or more tries, they should be notified in order to reduce the risk of users blocking themselves accidentally.
When the user successfully authenticates using a biometric, the number of tries for the PIN will be reset, and the user will no longer be blocked from entering their PIN.
Maximally avoid attackers from learning the user's PIN:
- implement your own PIN pad (do not use the standard numeric keyboard);
- disable screenshots or touch event logging while the user enters their PIN;
- use the
PINclass provided by the Mobile SDK for your platform (i.e.,
PinContaineron Android, and
PINon iOS). These classes have been designed to prevent that (partial) copies of the PIN remain in memory any longer than strictly necessarily. Additionally, they also implement utility functionality to check if the PIN is easy to guess.
The secondFactorInfo also informs you whether or not the user should be requested to present a biometric feature (showBiometrics). The Mobile SDK determines that biometrics should be shown, if all of the following are true:
- the device has support for biometrics that are considered sufficiently strong by the OS1;
- the user has enrolled at least one biometric feature;
- if a biometricsDisabled is configured, it is set to
- the session is not an enrolment (for creating a new account, the user's PIN is always required);
- when maxNumberSecondFactorWithoutPIN and/or maxTimeSecondFactorWithoutPIN have not been reached, if they are configured.
Avoid that users forget their PIN by asking them to input their PIN every once in a while. For example, the app could be configured to ask the user for their PIN after 30 subsequent biometric verifications or after 30 days since the last time the user entered their PIN.
Always present a biometric prompt to the user whenever biometrics are requested and allow user to authenticate using PIN as a secondary option.
After sending a PIN or biometric to the Mobile SDK for verification, you will receive an updated secondFactorInfo. Its result property will contain the result of the second factor verification:
- it's default state is
SUCCESS: the second factor was verified successfully with the backend;
ERROR: something went wrong, while verifying with the backend.
Next to the result, there is a boolean retry and a boolean blocked:
- retry indicates whether or not the user is allowed to retry. When
false, you will no longer be able to pass a second factor input to the mobile SDK;
- blocked indicates whether or not the user can still try another PIN code. For example, when the number of failed second factor tries equals the maximum number of tries,
blocked = true.
Android device vendors sometimes provide biometrics that, even though these can be used to unlock the phone, are not considered to be sufficiently strong with respect to the standards that are imposed by the Android OS. This is most notably the case for many face and iris recognition implementations. ↩