The user's PIN is relevant for several processes involving the XignIn technology and must always be kept secret. Therefore, in case a user is under the impression the PIN may have been compromised or simply wants to change it preemptively, the implementing app should offer such functionality.
In general, changing a PIN for an activation requires the same steps one can expect from any account management. First, users have to authenticate and provide the current PIN in order to prevent other actors to maliciously tamper with the account. Regardless of any additional authentication factors that may have been configured, the current PIN will always be required.
The following example shows how the process can be started. Note that since the SDK supports one activation per
XignIn-Manager, changing the PIN requires the idmIdentifier to be provided.
func startChangePin(idmIdentifier: String) throws {
// The personalizer handles numerous features to create, update and
// delete activations, which includes changing a PIN.
let personalizer: Personalizer = XignSdk.shared.personalizer
// Fetch authentication initialization data from the SDK, since the user
// has to authenticate (at least) with the PIN factor
let authInitData: AuthenticationInitializationData =
try personalizer.startChangePinSynchronous(idmIdentifier: idmIdentifier)
// Perform a regular authentication as described in authentication chapter.
// The user will have to provide the current PIN.
let authenticationResult: AuthenticationResult =
try YourImplementation.authenticateUser(authInitData)
// Check the authentication result. In order to be able to change the PIN,
// a result of type `.apiAccessChangePin` is required. All other results
// in this process have to be considered and handled as errors.
switch authenticationResult {
case .apiAccessChangePin(let apiAccessChangePin):
// An `ApiAccessChangePin` indicates the successful authentication of the user
// and contains additional information and functions for changing the PIN
try enterNewPin(apiAccessChangePin)
case .userLogin,
.serviceLogin,
.apiAccessAddFactor,
.apiAccessRequestNewActivationData,
.apiAccessDelete,
.apiAccessMergeComplete:
throw YourError.yourErrorCase
case .lockout:
// Receiving a lockout does not indicate an error in the process
// flow and has to be handled differently. Please refer to the
// section 'ErrorHandling' for detailed information.
YourImplementation.handleLockoutAndRepeatAuthentication()
}
}
fun startChangePin(idmIdentifier: String) {
// The personalizer handles numerous features to create, update and
// delete activations, which includes changing a PIN.
val personalizer: Personalizer = XignSdk.shared.personalizer
// Fetch authentication initialization data from the SDK, since the user
// has to authenticate (at least) with the PIN factor
val authInitData: AuthenticationInitializationData =
personalizer.startChangePinSynchronous(idmIdentifier = idmIdentifier)
// Perform a regular authentication as described in authentication chapter.
// The user will have to provide the current PIN.
val authenticationResult: AuthenticationResult =
YourImplementation.authenticateUser(authInitData)
// Check the authentication result. In order to be able to change the PIN,
// a result of type `AuthenticationResult.ApiAccessChangePin` is required.
// All other results in this process have to be considered and handled as errors.
when (authenticationResult) {
is ApiAccessChangePin -> {
// An `ApiAccessChangePin` indicates the successful authentication of the user
// and contains additional information and functions for changing the PIN
enterNewPin(authenticationResult)
}
is ApiAccessAddFactor,
is ApiAccessMergeComplete,
is ApiAccessRequestNewActivationData,
is ServiceLoginResult,
is UserLoginResult,
is ApiAccessDelete -> {
YourException()
}
is Lockout -> {
// Receiving a lockout does not indicate an error in the process
// flow and has to be handled differently. Please refer to the
// section 'ErrorHandling' for detailed information.
YourImplementation.handleLockoutAndRepeatAuthentication()
}
}
}
After a successful authentication, the user has to be asked to provide the new PIN which must conform to the
requirements for new PINs that can be retrieved from the authentication result obtained by the previous step. Checking
the requirements by examining the PinSpecification must not be skipped since updated security policies may require the
minimum PIN length to be longer or the maximum PIN length to be shorter than in the past. When the SDK deems the new PIN
to be valid with respect to this specification, the process can be finished in the third and last step.
func enterNewPin(_ apiAccessChangePin: ApiAccessChangePin) throws {
// Retrieve the personalization component used to update the activation.
let personalizer: Personalizer = XignSdk.shared.personalizer
// Retrieve the PIN specification to determine the length requirements
// applicable to a new PIN.
let pinSpec: PinSpecification = apiAccessChangePin.pinSpec
var isPinValid: Bool = false
var errorText: String? = nil
while !isPinValid {
// Ask the user to input the new PIN and optionally show previous errors.
let newPin: String = YourImplementation.askUserForPin(
minLength: pinSpec.minLength,
maxLength: pinSpec.maxLength,
errorText: errorText
)
// Supply the new PIN to the `pinSpec` and check the result afterwards.
let pinError: PinValidator.ResultCode = pinSpec.setPin(newPin)
switch pinError {
case .valid:
// The new PIN is considered to be valid and the updated api access
// object can be used to finalize the process.
isPinValid = true
case .empty:
errorText = "PIN must not be empty"
case .onlyNumbers:
errorText = "Only numbers are allowed"
case .tooShort:
errorText = "PIN must be at least \(pinSpec.minLength) digits long"
case .tooLong:
errorText = "PIN can't be longer than \(pinSpec.maxLength) digits"
}
}
// Invoke the final the step after a valid PIN has been supplied to the
// `PinSpecification` within the `ApiAccessChangePin` object.
try personalizer.finishChangePinSynchronous(request: apiAccessChangePin)
// After this function has been successfully executed, the process of
// changing a PIN is complete.
}
fun enterNewPin(apiAccessChangePin: ApiAccessChangePin) {
// Retrieve the personalization component used to update the activation.
val personalizer: Personalizer = XignSdk.shared.personalizer
// Retrieve the PIN specification to determine the length requirements
// applicable to a new PIN.
val pinSpec = apiAccessChangePin.pinSpec
var isPinValid: Boolean = false
var errorText: String? = null
while (!isPinValid) {
// Ask the user to input the new PIN and optionally show previous errors.
val newPin: String = YourImplementation.askUserForPin(
minLength = pinSpec.minLength,
maxLength = pinSpec.maxLength,
errorText = errorText
)
// Supply the new PIN to the `pinSpec` and check the result afterwards.
val pinError: PinValidator.ErrorCode = pinSpec.setPin(newPin)
when (pinError) {
PinValidator.ErrorCode.VALID -> {
// The new PIN is considered to be valid and the updated api access
// object can be used to finalize the process.
isPinValid = true
}
PinValidator.ErrorCode.EMPTY ->
errorText = "PIN must not be empty"
PinValidator.ErrorCode.ONLY_NUMBERS ->
errorText = "Only numbers are allowed"
PinValidator.ErrorCode.TOO_SHORT ->
errorText = "PIN must be at least ${pinSpec.minLength} digits long"
PinValidator.ErrorCode.TOO_LONG ->
errorText = "PIN can't be longer than ${pinSpec.maxLength} digits"
}
}
// Invoke the final the step after a valid PIN has been supplied to the
// `PinSpecification` within the `ApiAccessChangePin` object.
personalizer.finishChangePinSynchronous(request = apiAccessChangePin)
// After this function has been successfully executed, the process of
// changing a PIN is complete.
}