The authentication process can be finished by invoking Authenticator.finishAuthentication(userInfo:)
with the signed AuthenticationUserInformation. The result is an enum (a sealed class in Kotlin). The next code
example shows how this step can be implemented; the cases are explained afterwards.
private func finishAuthentication(userInformation: AuthenticationUserInformation) throws {
let authenticator = XignSdk.shared.authenticator
// Submit the previous signed `AuthenticationUserInformation` object to the XignIn-Manager.
let result: AuthenticationResult = try authenticator.finishAuthenticationSynchronous(
userInfo: userInformation
)
switch result {
case .userLogin(let userLoginResult):
// The end of a normal user login. The userLoginResult contains some meta information.
return
case .serviceLogin(let serviceLoginResult):
// The end of the authentication during an InApp-Authentication process. The
// serviceLoginResult is needed to request the user's attribute data as well as
// the MappedId.
// TODO: finish the inApp-Authentication
return
case .apiAccessAddFactor(let apiAccessAddFactor):
// A special result needed to subsequently add a factor, needs further handling.
return
case .apiAccessChangePin(let apiAccessChangePin):
// A special result needed to change the user's PIN, needs further handling.
return
case .apiAccessMergeComplete(idmIdentifier: let idmIdentifier):
// Signalizes the success of an account merge.
return
case .apiAccessRequestNewActivationData(let apiAccessRequestNewActivationData):
// A special result needed to request a new activation, needs further handling.
return
case .apiAccessDelete(let apiAccessDelete):
// An `apiAccessDelete` indicates the successful authentication in order to
// perform a delete action, needs further handling.
return
case .lockout(
lockoutInformation: let lockoutInformation,
authenticationUserInformation: let authenticationUserInformation
):
// Happens, if one of the supplied authenticators was invalid, e.g. wrong PIN.
// In this case the lockout duration within `lockoutInformation` must be
// waited. After that all required factors must be supplied again and the
// process can be retried.
// Check if the lockout is permanent.
if lockoutInformation.isPermanent {
// The activation has been disabled permanently, notify the user an cancel the process.
throw YourError.yourErrorCase
}
// Retrieve the date until which the lock is effective.
let lockedUntil: Date = lockoutInformation.lockedUntil
// Wait until the lock has been lifted.
// Retry the signing of the `authenticationUserInformation`.
// Note: This is a call to the previous documentation example function that
// illustrates the singing.
try signAuthentication(userInformation: authenticationUserInformation)
return
}
}
private fun finishAuthentication(userInformation: AuthenticationUserInformation) {
val authenticator: Authenticator = XignSdk.shared.authenticator
// Submit the previous signed `AuthenticationUserInformation` object to the XignIn-Manager.
val result: AuthenticationResult = authenticator.finishAuthenticationSynchronous(
userInfo = userInformation
)
when (result) {
is UserLoginResult -> {
// The end of a normal user login. The userLoginResult contains some meta information.
return
}
is ServiceLoginResult -> {
// The end of the authentication during an InApp-Authentication process. The
// serviceLoginResult is needed to request the user's attribute data as well as
// the mapping Id.
// TODO: finish the inApp-Authentication
return
}
is ApiAccessAddFactor -> {
// A special result needed to subsequently add a factor, needs further handling.
return
}
is ApiAccessChangePin -> {
// A special result needed to change the user's PIN, needs further handling.
return
}
is ApiAccessMergeComplete -> {
// Signalizes the success of an account merge.
return
}
is ApiAccessRequestNewActivationData -> {
// A special result needed to request a new activation, needs further handling.
return
}
is ApiAccessDelete -> {
// An `apiAccessDelete` indicates the successful authentication in order to
// perform a delete action, needs further handling.
return
}
is Lockout -> {
val lockoutInformation: LockoutAttemptInformation = result.lockoutInformation
val authenticationUserInformation: AuthenticationUserInformation =
result.authenticationUserInformation
// Happens, if one of the supplied authenticators was invalid, e.g. wrong PIN.
// In this case the lockout duration within `lockoutInformation` must be
// waited. After that all required factors must be supplied again and the
// process can be retried.
// Check if the lockout is permanent.
if (lockoutInformation.isPermanent) {
// The activation has been disabled permanently,
// notify the user and cancel the process.
throw YourException()
}
// Retrieve the date until which the lock is effective.
val lockedUntil: Instant = lockoutInformation.lockedUntil
// Wait until the lock has been lifted.
// Retry the signing of the `authenticationUserInformation`.
// Note: This is a call to the previous documentation example function that
// illustrates the signing.
signAuthentication(userInformation = authenticationUserInformation)
return
}
}
}
As mentioned in the beginning of the Authentication chapter the authentication process is also used
by various other processes, e.g. change PIN or add factor, therefore the final result of the authentication process
changes depending on how the processes was started. Some of these results mark the end of the process, others however
need further handling as mentioned within the inline comments in the previous examples. The implementation of the result
object differ a little between Swift and Kotlin. In Swift most enum cases contain one parameter which is an instance of
the type that is needed to continue the process, whereas in Kotlin the case is the type. For example, the parameter of
the case AuthenticationResult.apiAccessChangePin(:) is of the type ApiAccessChangePin and in Kotlin the concrete
subclass of the AuthenticationResult is of the type AuthenticationResult.ApiAccessChangePin. For enum cases that
provide more than one parameter or the parameter's type is of a standard class (e.g. String), the Kotlin
implementation is a wrapper object that contains these parameters as properties. In the following, all cases are
discussed in detail using the previous Swift example:
The case .userLogin(let userLoginResult) marks the end of simple user authentication. It can be expected when the
authentication has been started by scanning a QR code or handling a Deep-Link as described in the
chapters QR code
and Deep-Links.
No further handling is required in this case. The returned parameter of the type UserLoginResult contains some
metadata, e.g. roleName (the used role) and the serviceInformation, that optionally can be displayed to the user
or processed otherwise like being persisted in an authentication history.
The case .serviceLogin(let serviceLoginResult) is part of the InApp-Authentication. It can be expected when the
authentication has been started by Authenticator.fetchInAppAuthenticationInitializationData(:) as described in the
chapter Starting an InApp-Authentication. This case contains
an instance of ServiceLoginResult which is needed to fetch the OIDC authorization code. Therefore, the started
process is not finished yet and must be continued by invoking Authenticator.fetchAuthorizationCode(:). For further
details please refer to the
chapter Finishing an InApp-Authentication.
Additionally, some meta information like the serviceInformation are included as well and can optionally be
displayed or processed otherwise, e.g., for an authentication history.
The case .apiAccessAddFactor(let apiAccessAddFactor) is returned when the authentication has been started with the
result of the function Personalizer.startAddAuthenticationFactor(:) to add a factor to the current
personalization, e.g. biometric. The returned parameter ApiAccessAddFactor is needed to continue the process. This
object needs further handling before is can be used to finish the process. Please take a look at the
chapter Add factor for that purpose.
The case .apiAccessChangePin(let apiAccessChangePin) can be expected if the authentication has been started in order
to change the PIN afterwards. The returned parameter ApiAccessChangePin needs to be supplied with the new PIN
before invoking Personalizer.finishChangePin(request:) to finish the process. For more information please refer to the
chapter Change PIN.
The case .apiAccessMergeComplete(idmIdentifier: let idmIdentifier) signalizes the end of a successful account merge in
the scenario of an organization invite. This result can be expected if the authentication has been started with
the AuthenticationInitializationDataWithSession from PersonalizationResponse.mergePersonalization(::) of the
personalization process as described in the
chapter Decrypting the PersonalizationInitializationData
. After receiving this result the user should be informed that the activation QR code from the organization invite email
has become invalid and can be discarded. Otherwise, no further action is required.
The case .apiAccessRequestNewActivationData(let apiAccessRequestNewActivationData) is part of the request a new
activation process. It can be expected if the authentication has been started with the result of the
function Personalizer.startRequestNewActivationData(idmIdentifier:). The parameter of the
type ApiAccessRequestNewActivationData is needed to continue the process. It must be supplied with a new activation
PIN and optionally with an alias for the new activation before the process can be finished by invoking
Personalizer.finishRequestNewActivationDataSynchronous(:). For more information please take a look at the chapter
Request a new Activation.
The case .apiAccessDelete(let apiAccessDelete) indicates a successful authentication in order to perform a delete
action. It can be expected if the authentication has been started with the result of the function
Personalizer.startDeletetion(idmIdentifier). The returned parameter ApiAccessDelete needs to be supplied to
Personalizer.finishDeletion(request:) in order to finish the process. Further information can be found in the chapter
Delete Account.
Finally, the last case .lockout(lockoutInformation:authenticationUserInformation:) is a special case and can occur in
every process. It does not depend on how this process was started, but on whether the supplied signatures of
the AuthenticationUserInformation were valid or not. Similar to the personalization process this can happen, if for
example the wrong PIN was entered by the user. In this case two objects are returned, the LockoutInformation and
the AuthenticationUserInformation. The LockoutInformation contains a period of time the user must wait until the
process can be repeated. For more information about the lockout handling, please refer to the
chapter Lockout Handling. If possible, the process can be repeated from the previous step
Signing of the authentication request with the
given AuthenticationUserInformation after the lockout duration has passed. Note that all previous supplied signatures
haven been cleared, because at least one of them was invalid. For security reasons, the exact authenticator that was
invalid cannot be disclosed.