Performing Operations
- Performing Operations
Overview
The NevisAuthenticationSession
class conforms to different protocols that define the operations exposed by the SDK. The NevisOperations
protocol specifies the standard FIDO UAF 1.1 operations, also described as in-band operations. In addition, the SDK also supports operations that are not standard FIDO service but proprietary NEVIS Mobile Authentication backend functionality, built on top of the FIDO standards. Those features include out-of-band operations and dispatch target management defined by the OutOfBandOperations
. Though OutOfBandOperations
protocol is also part of NevisOperations
protocol.
The NevisOperationsMultiAccount
extends NevisOperations
protocol to make all operation multi-account capable. This is the protocol should be implemented if you intend to use the multi-account feature of the SDK.
⚠️ WARNING: If you don’t need multi-account, we advise to use the
NevisOperations
protocol.
Under the hood, the SDK performs all requests that are required for communicating with the NEVIS Mobile Authentication backend and interacts with the FIDO Client, which implements the UAF
protocol. Your application shouldn’t need to interact with the FIDO Client directly though.
The following operations are supported:
Registration: allow to register an existing FIDO authenticator with the user’s account at the relying party, in accordance with the relying party policy. Registration optionally handles the creation of the dispatch target, based on the provided
DispatchTargetConfiguration
.Authentication: allow to prompt the user to authenticate using a previously registered FIDO authenticator.
Transaction Confirmation: In addition to providing a general authentication prompt, allow to prompt the user to confirm a specific transaction. The goal of this additional authentication operation is to enable relying parties to ensure that the user is confirming a specified set of the transaction details (instead of authenticating a session to the user agent).
Deregistration: trigger the deletion of the account-related authentication key material.
OpenSettings: asks an authenticator to display its specific settings interface, if available.
Dispatch Target: A dispatch target describes a destination to which the NEVIS Mobile Authentication backend can dispatch a token. For instance it can be the registration token that can be used to send Push notifications to an application in a mobile device. This operation supports only the updating and the deletion of the dispatch target, that was created during the registration.
Note
During an operation, the provideduserInteractionDelegate
will be called to let your app deal with user interaction. For information about how to implement a user interaction delegate, see User Interaction Delegation.Note
Considering that the only supported authorization of SDK HTTP requests is based on session cookies, the SDK must always be supplied with the latest valid session cookies supplied by NEVIS Mobile Authentication backend for all Nevis Operations.
General outline of an SDK Operation
- The application calls a specific operation which is executed asynchronously.
- The SDK at some point during the execution of the operation will require app interaction with the user in order to provide necessary information, it waits for an answer from the application.
- The App calls the completion handler of the SDK user interaction delegate function with an outcome object. This provides the SDK with the required information it was waiting for previously (such as entering a PIN or providing a fingerprint).
- The SDK now completes the operation which was started in step 1, and returns the result of the operation to the user via the completion handler of the operation started in step 1.
Out-of-Band Registration and Authentication
Out-of-band operations happen when a message is delivered to the application via a channel like a Push notification, or a QR code. The application is responsible to parse that message in order to create an OutOfBandPayload
object.
For example, this is how you could obtain a payload based on a UNNotificationContent
object:
if let data = content.userInfo["data"] as? String, let version = content.userInfo["version"] as? Int {
let payload = OutOfBandPayload(data: data, format: .json, version: version, channel: .push)
}
Then you simply call process(payload:dispatchTargetConfiguration:userInteractionDelegate:completion:)
to trigger the operation. In case of success, the result will contain the type of operation that was executed, which allows you to react accordingly.
let userInteractionDelegate: UserInteractionDelegate = ...
session.process(payload: payload, dispatchTargetConfiguration: nil, userInteractionDelegate: userInteractionDelegate) { [unowned self] result in
switch result {
case let .success(operation):
os_log("The operation succeeded.")
case let .failure(error):
os_log("Handle operation failure.")
}
}
In order to enable out-of-band authentication, you also need to register the device as a dispatch target. The supported way is to pass the required information as a DispatchTargetConfiguration
object to the process(payload:dispatchTargetConfiguration:userInteractionDelegate:completion:)
method, so you get a single result that indicates a success if the whole process succeeds, or an error if anything goes wrong. See Dispatch Target Management for more details regarding updating and deleting of the dispatch target.
Note
ThedispatchTargetConfiguration
parameter is only intended to be used by the SDK in case of an out-of-band registration, and will be ignored in other operations.Note
Within the registration process the SDK sends theidentifierForVendor
(as a device ID), to the NEVIS Mobile Authentication Backend. This ID is stored as an attribute of the registered authenticator, and the dispatch target. With this information it is easier to identify those authenticators and dispatch targets which belong to the same device when administrating the UAF credentials.The
identifierForVendor
is the most unique identifier for an iOS device which can be retrieved programmatically. (See related Apple documentation)
Username-less Authentication
It is possible to start an out-of-band authentication without a username in the initial FIDO request. In this scenario, the operation allows to authenticate with any previously registered account. If the application is required to support this scenario and handles multiple accounts, then it has to implement the AuthenticationUserInteractionDelegate
protocol which needs to be provided as the UserInteractionDelegate
when invoking the process(payload:dispatchTargetConfiguration:userInteractionDelegate:completion:)
method.
Note
In most cases, implementing theUserInteractionDelegate
is enough unless there is a requirement to support username-less authentication.
In-Band Registration
You perform an in-band FIDO registration in your app using the register(username:dispatchTargetConfiguration:authorizationProvider:userInteractionDelegate:completion:)
method.
You first need to create an authorization provider, a user interaction delegate and pass them to the registration method, which will return a result asynchronously.
let sessionCookie = HTTPCookie()
let authorizationProvider = CookieAuthorizationProvider([sessionCookie])
let userInteractionDelegate: UserInteractionDelegate = ...
session.register(username: <username>, dispatchTargetConfiguration: nil, authorizationProvider: authorizationProvider, userInteractionDelegate: userInteractionDelegate) { [unowned self] result in
switch result {
case .success:
// The user was successfully registered.
case let .failure(error):
// Handle registration failure.
}
}
Alternatively JWT based authorization provider can be used:
let authorizationProvider = JwtAuthorizationProvider(jwt)
If you want to enable out-of-band authentication, you will need to register the device as a dispatch target. The supported way is to pass the required information as a DispatchTargetConfiguration
object to the register(username:dispatchTargetConfiguration:authorizationProvider:userInteractionDelegate:completion:)
method, so you get a single result that indicates a success if the whole process succeeds, or an error if anything goes wrong. See Dispatch Target Management for more details regarding updating and deleting of the dispatch target.
In-Band Authentication
An in-band authentication is performed when the application tries to access the Web server and NEVIS detects that it is not authenticated. In that case, you should get a 401
HTTP status code.
You call authenticate(sessionProvider:userInteractionDelegate:completion:)
in order to authenticate the user with server-specified authenticators, and get back a valid AuthorizationProvider
that you can use while retrying your initial request.
let userInteractionDelegate: UserInteractionDelegate = ...
session.authenticate(userInteractionDelegate: userInteractionDelegate) { [unowned self] result in
switch result {
case let .success(authorizationProvider):
retry(using: authorizationProvider)
case let .failure(error):
// Handle authentication failure.
}
}
If the Nevis Mobile Authentication SDK is not used as first factor authentication, an additional SessionProvider
must be passed to authenticate(sessionProvider:completion:)
in order to authenticate with FIDO UAF successfully.
CookieSessionProvider
and JwtSessionProvider
are the supported implementations of the SessionProvider.
let userInteractionDelegate: UserInteractionDelegate = ...
// Retrieved after the first factor authentication.
let cookies: [HTTPCookie]
let sessionProvider = CookieSessionProvider(cookies)
// Alternatively:
// let sessionProvider = JwtSessionProvider(jwt)
session.authenticate(sessionProvider, userInteractionDelegate: userInteractionDelegate) { [unowned self] result in
switch result {
case let .success(authorizationProvider):
let cookies = (authorizationProvider as? CookieAuthorizationProvider)?.cookies
let token = (authorizationProvider as? JwtAuthorizationProvider)?.jwt
retry(using: jwt ?? token)
case let .failure(error):
// Handle authentication failure.
}
}
Protected Operations
In certain cases it is necessary for the SDK to execute operations that are protected. For example a registration is typically a protected operation: registering a device will allow the end-user to access some protected systems, so not everyone should be allowed to register. This implies that, before registering, the end user will be required to authenticate. As a result of this authentication, an authorization token is generated and this authorization token grants access to the deregistration service in the backend.
Other example of protected operations are deregistration and dispatch target deletion (removing credentials requires authorization as well).
The SDK method calls for such operations require an implementation of an
AuthorizationProvider
.
This implementation will provide the necessary authorization for the request to complete successfully.
Depending on the configuration of the backend, it may be that such an authorization credential can be fetched using FIDO UAF Authentication. However, to ensure flexibility for other eventualities the responsibility to retrieve the credential has been delegated to the application, and as such an authentication operation should be carried out first before attempting to access any resource that is considered protected, even a FIDO Operation.
Although not recommended, it is also possible to leave such resources unprotected, in which case an empty implementation of the provider will suffice.
1 The developer of the application knows that the deregister endpoint is protected by FIDO authentication and performs an in band authentication
2-4 The operation completes successfully
5 The session cookie in this specific example is provided by an Authorization Provider to the SDK to allow it to deregister
Session Provider and Second Factor Authentication
In the case of In Band Authentication, the backend may be configured such that FIDO UAF Authentication is a second or third factor authenticator. In such cases NEVISProxy will have already created a session, and the credentials for this session should be used when executing an authentication operation, in order for the flow to be correctly recognized in the backend.
For a more detailed explanation please refer to the SessionProvider
.
Transaction Confirmation
In addition to providing a general authentication prompt, FIDO UAF offers support for prompting the user to confirm a specific transaction. This prompt includes the ability to communicate additional information to the client for display to the end user, using the client’s transaction confirmation display.
Since a transaction confirmation is nothing else than an authentication operation that contains additional information, you can refer to Out-of-Band Registration and Authentication for more details.
Deregistration
You perform a FIDO deregistration by calling the following methods depending on the mode you want to deregister:
deregisterAuthenticator(authorizationProvider:userInteractionDelegate:completion)
. Deregisters a specific authenticator registration. Referred to asaaid
mode in FIDO specification.deregisterDevice(authorizationProvider:userInteractionDelegate:completion)
. Deregisters all authenticator registrations on the current device. Referred to asaaid_and_keyid
mode in FIDO specification.
Note
The Dispatch Target Deletion is called by the SDK in case of deregistration after the given deregistration mode is executed successfully.
let userInteractionDelegate: DeregistrationUserInteractionDelegate = ...
session.deregisterAuthenticator(userInteractionDelegate: userInteractionDelegate) { [unowned self] result in
switch result {
case .success:
// The user was successfully deregistered.
case let .failure(error):
// Handle deregistration failure.
}
}
session.deregisterDevice(userInteractionDelegate: { userInteractionDelegate) { [unowned self] result in
...
}
Dispatch Target Management
The purpose of dispatch targets is to serve as receivers of out-of-band messages. Dispatch target management is important for any NEVIS Mobile Authentication client application that wants to be able to receive and handle out-of-band messages.
Dispatch Target Registration
In a case where dispatching takes place in the form of push messages, the application is responsible for registering itself as a dispatch target with the NEVIS Mobile Authentication backend.
For example, you can register the device as a dispatch target to receive Push notifications via Google Firebase Cloud Messaging. You need to pass as argument the FCM token used to identify the device, as well as a user-friendly name that helps the user to identify this target.
The supported way to register the device as a dispatch target is to pass a DispatchTargetConfiguration
object as part of an Out-of-Band Registration or an In-Band Registration
Note
The SDK will automatically send public asymmetric keys to the server. Those keys are used to sign a dispatch target modification payload and to decryptOutOfBandPayload
‘s content.
Dispatch Target Modification
If the dispatch target identifier changes, as it may be the case for a Push notification or Firebase token, the application has to inform the server about that change. The same goes for dispatch target name changes.
let token = Messaging.messaging().fcmToken
let name = UIDevice.current.name
session.updateDispatchTarget(identifier: token, name: name) { [unowned self] result in
switch result {
case .success:
// The dispatch target was successfully updated.
case let .failure(error):
// Handle dispatch target modification failure.
}
}
The SDK will check whether the provided identifier and name are different from the existing one, and only communicate actual changes. This allows the application to update dispatch target information at any given point in time without any further logic.
Dispatch Target Deletion
Dispatch target deletion allows to remove the current device as dispatch target. You simply call deleteDispatchTarget(authorizationProvider:)
for the target to be deleted:
let sessionCookie = HTTPCookie()
let authorizationProvider = CookieAuthorizationProvider([sessionCookie])
// Alternatively:
// let authorizationProvider = JwtAuthorizationProvider(jwt)
session.deleteDispatchTarget(authorizationProvider: authorizationProvider) { [unowned self] result in
switch result {
case .success:
// The dispatch target was successfully removed.
case let .failure(error):
// Handle dispatch target deletion failure.
}
}
Note
As the backend endpoint for deleting dispatch target is considered to be protected, passingAuthorizationProvider
in the SDK invocation might be required.
Multi-account
In case you want to allow end-users to register multi-accounts, the overloaded methods in NevisOperationsMultiAccount
have to be used.
- Registration: It is identical to its single account counterpart, as the username is also present there:
register(username:dispatchTargetConfiguration:authorizationProvider:userInteractionDelegate:completion:)
For single-account see: In-Band Registration
- Authentication:
authenticate(username:sessionProvider:userInteractionDelegate:completion:)
For single-account see: In-Band Authentication
- Deregistration:
- Authenticator:
deregisterAuthenticator(username: authorizationProvider:userInteractionDelegate:completion)
- Account:
deregisterAccount(username: authorizationProvider:userInteractionDelegate:completion)
- Authenticator:
For single-account see: Deregistration
- Dispatch Target Deletion:
deleteDispatchTarget(for username:authorizationProvider:onCompletion)
For single-account see: Dispatch Target Deletion
⚠️ WARNING: In case the overloaded function in
NevisOperationsMultiAccount
were already used to register more than one account in the SDK, using the single account counterparts fromNevisOperations
will result a failed operation with an error. This is to prevent accidental misuse of the single-account APIs. See the following example:Example:
- Step 1: Register an authenticator for two different account first.
- Step 2: Call the single account version of deregister:
deregisterDevice(authorizationProvider:userInteractionDelegate:completion)
Device deregistration will result
FIDOError.protocolError
as an underlying error ofNevisError
.List of methods result in
FIDOError.protocolError
in case of multi-account:
NevisOperations
authenticate(sessionProvider:userInteractionDelegate:completion:)
deregisterAuthenticator(authorizationProvider:userInteractionDelegate:completion)
deregisterDevice(authorizationProvider:userInteractionDelegate:completion)
deleteDispatchTarget(authorizationProvider:)
LocalDatamanager
deleteAuthenticator(aaid:completion:)
deleteDispatchTarget(completion:)
Multi-account extensions
With the multi account feature, the Nevis Mobile Authentication SDK’s API has been extended to provide access to the registered accounts.
The SDK offers the capability to register, query and delete accounts, but does not keep track of the actively used account. This means that the mobile application integrating the SDK has to provide the functionality, which allows the end user to select a registered account for the current operation.
AuthenticatorInformation
has been extended with account related information. See for example its UserEnrollment
and Registration
properties.
The LocalDataManager
is intended to be used by application developers to query the SDK for authenticator and account related information.
Tip
It is capable of returning all registered accounts by calling its
accounts()
function.To identify which authenticator is registered for an account, query all authenticators with
LocalDataManger.authenticators()
and process its result. Collect all authenticators whereAuthenticatorInformation.registration.registeredAccounts
contains the desired account.
⚠️ WARNING
LocalDataManager
is also capable of deleting a registration, but it is really important to note that it can only delete information locally and do not communicate with the backend!
Removing data from the backend as well can be achieved by starting a deregister operation using the NevisOperationsMultiAccount
protocols deregister methods deregisterAuthenticator
and deregisterAccount
.