Delete Mobile Biometrics

Removes native mobile biometrics for the user using the client SDK.

About client-facing steps

A journey is a sequence of steps that are executed when it's invoked by a client application (known as the "client"). Some steps require involvement from the client, such as collecting user input. Other steps, like validating a token, are executed in the backend by the Mosaic journey engine alone.

When invoked, the journey begins executing the steps while the client waits for further instructions. When a journey reaches a client-facing step, the journey asks the client for the required input and then waits for the client to respond. The client presents their own UI if user interaction is required, and returns input to the journey. The journey then proceeds in a similar manner until it's completed.

Description

This client-facing step is used to remove biometric credentials from a user’s mobile device, and their registration from the server. It is typically triggered in scenarios such as when a user registers their biometrics on a new device and the system needs to deregister biometrics from the old one to enforce a single-device policy, or when the user explicitly requests the deletion of their biometrics from a specific device as part of a cleanup process.

When this step is initiated, your application instructs Mosaic's mobile SDK to remove the biometric credentials associated with the device. After the SDK completes the removal process, the application sends the result, including the key_ID, back to the journey using the IDO SDK. Mosaic's backend uses this key ID to finalize the removal process via the Delete Mobile Biometrics API. If the user is not logged in, the journey will either fail or proceed to a branch handling the “User not logged in” scenario.

To support biometric removal, you’ll need to:

Configuration

Field Description
User Auth State Indicates if the user has authenticated in this journey. Must be set to The user is already authenticated, so that the user context is provided implicitly by the journey.
Error Output Variable Name of the variable that stores any errors returned by the step.
Failure Behavior Determines the behavior in case of failure, which either aborts the journey or proceeds to a failure branch of the control flow (default).

Examples

This section provides two key examples where to enforce the Delete Mobile Biometrics step:

Example 1: Enforcing a single mobile device policy

In organizations that enforce a policy allowing biometric registration on only one mobile device per user, the Delete Mobile Biometrics step ensures compliance. If a user has registered their biometrics on a new device, an attempt to use an older device to log in can be intercepted by the journey and redirect to a cleanup of the old registration. This ensures that only the new device retains the biometric credentials, enhancing security by reducing the risk of unauthorized access from multiple devices.

Execute the following code snippet when the journey reaches the Delete Mobile Biometrics step. You’ll need to provide the userId associated with the user’s biometric credentials, which is dynamically provided in the journey’s response under response.data.user_identifier, as well as the publicKeyId that uniquely identifies the biometrics on the device. After the mobile SDK successfully removes the biometrics, the publicKeyId returned by the SDK should be included in the data sent back to the IDO service to complete the step.

SwiftKotlin
Copy
Copied
private func handleIdoResponse(_ response: IdentityOrchestration.TSIdoServiceResponse) {
    guard let responseStepId = response.journeyStepId else { debugPrint("[DEBUG]: Missing step id in IDO response"); return }
    
    switch responseStepId {
    case .deleteMobileBiometrics:
        guard let userId = response.data?["user_identifier"] as? String else { 
            debugPrint("[DEBUG]: Missing user identifier in response") 
            return 
        }
        TSAuthentication.shared.unregistersNativeBiometrics(username: userId) { response in
            switch response {
            case .success(let result):
                let data = ["publicKeyId": result.publicKeyId]
                
                TSIdo.submitClientResponse(clientResponseOptionId: .clientInput, data: data)
            case .failure(let error):
                // Handle the error
                debugPrint("[DEBUG]: Error: \(error)")
            }
        }
    default:
        break
    }
}
Copy
Copied
data class BiometricsUnregistrationResult(val publicKeyId: String)

private fun processServiceResponse(idoResponse: TSIdoServiceResponse) {
    when (idoResponse.journeyStepId) {
        TSIdoJourneyActionType.UnregisterNativeBiometrics.type -> handleUnregisterBiometrics(idoResponse)
    }
}

private fun handleUnregisterBiometrics(idoResponse: TSIdoServiceResponse) {
    val userId = idoResponse.responseData?.optString("user_identifier")
    activity?.applicationContext?.let {
        TSAuthentication.unregisterNativeBiometrics(it, userId, object:
            TSAuthCallback<TSBiometricsUnregistrationResult, TSBiometricsUnregistrationError> {
            override fun error(error: TSBiometricsUnregistrationError) {
                Log.e(TAG, "Failed to unregister biometrics. Error: " + error.message)
                //TODO: handle error
            }

            override fun success(result: TSBiometricsUnregistrationResult) {
                Log.d(TAG, "Biometrics unregistration success")
                submitResponse(TSIdoClientResponseOptionType.ClientInput.type, BiometricsUnregistrationResult(result.keyId()))
            }
        })
    }
}

After executing the code snippet, Mosaic’s backend processes thepublicKeyIdto finalize the removal of the biometric credentials from the previous device. This ensures that the user’s biometrics are only active on the newly registered device, maintaining compliance with your organization’s single-device policy. The journey then continues, either moving to the next step or concluding based on the configured flow.

Example 2: Biometric removal as part of cleanup in onboarding

During an onboarding journey, a user might begin the registration process but fail to complete it due to an issue or error. In such cases, the Delete Mobile Biometrics step is used as part of the cleanup process to remove any partially registered biometric data. This allows the user to restart the onboarding journey without encountering conflicts or duplicate registrations.

Execute the following code snippet when the journey reaches the Delete Mobile Biometrics step. You’ll need to provide the username associated with the user’s biometric credentials, as well as the publicKeyId that uniquely identifies the biometrics on the device. After the mobile SDK successfully removes the biometrics, the publicKeyId returned by the SDK should be included in the data sent back to the IDO service to complete the step.

SwiftKotlin
Copy
Copied
private func handleIdoResponse(_ response: IdentityOrchestration.TSIdoServiceResponse) {
    guard let responseStepId = response.journeyStepId else { debugPrint("[DEBUG]: Missing step id in IDO response"); return }
    
    switch responseStepId {
    case .deleteMobileBiometrics:
        guard let userId = response.data?["user_identifier"] as? String else { 
            debugPrint("[DEBUG]: Missing user identifier in response") 
            return 
        }
        TSAuthentication.shared.unregistersNativeBiometrics(username: userId) { response in
            switch response {
            case .success(let result):
                let data = ["publicKeyId": result.publicKeyId]
                
                TSIdo.submitClientResponse(clientResponseOptionId: .clientInput, data: data)
            case .failure(let error):
                // Handle the error
                debugPrint("[DEBUG]: Error: \(error)")
            }
        }
    default:
        break
    }
}
Copy
Copied
data class BiometricsUnregistrationResult(val publicKeyId: String)

private fun processServiceResponse(idoResponse: TSIdoServiceResponse) {
    when (idoResponse.journeyStepId) {
        TSIdoJourneyActionType.UnregisterNativeBiometrics.type -> handleUnregisterBiometrics(idoResponse)
    }
}

private fun handleUnregisterBiometrics(idoResponse: TSIdoServiceResponse) {
    val userId = idoResponse.responseData?.optString("user_identifier")
    activity?.applicationContext?.let {
        TSAuthentication.unregisterNativeBiometrics(it, userId, object:
            TSAuthCallback<TSBiometricsUnregistrationResult, TSBiometricsUnregistrationError> {
            override fun error(error: TSBiometricsUnregistrationError) {
                Log.e(TAG, "Failed to unregister biometrics. Error: " + error.message)
                //TODO: handle error
            }

            override fun success(result: TSBiometricsUnregistrationResult) {
                Log.d(TAG, "Biometrics unregistration success")
                submitResponse(TSIdoClientResponseOptionType.ClientInput.type, BiometricsUnregistrationResult(result.keyId()))
            }
        })
    }
}

Once the biometric data is removed via the SDK, Mosaic’s backend processes thepublicKeyIdto clean up any residual biometric credentials from the failed onboarding attempt. This allows the user to restart the onboarding journey without any issues related to previously registered biometrics. The journey then either retries the registration or moves to a different branch, depending on how the flow is configured.