# Mobile PIN Authentication

div
div
Client SDK
div
Mobile approve
div
SSO
div
Sub-journey
> Authenticates the user with an app-specific PIN code


## 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 to collect 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 authenticate the user using an app-specific PIN code they registered previously (using the [Register Mobile PIN](/guides/orchestration/journeys/register_mobile_pin) step).

Once triggered, this step instructs the client to prompt the user for their PIN and perform a signing operation on a challenge provided by the journey. The client uses the Authentication SDK together with the code and the challenge to generate a signature, and submits the result back to the journey using the Orchestration SDK.

If successful, the journey sets the user context to the authenticated user and continues to the next step. User tokens generated upon authentication can be accessed in subsequent steps using `@policy.userContext()`. If the step fails or is cancelled, the journey either aborts or continues to a failure or cancel branch if configured.

To support mobile PIN authentication, you'll need to:

* Implement PIN registration as described in [Register Mobile PIN](/guides/orchestration/journeys/register_mobile_pin)
* Implement the Authentication SDK call required for authentication (see [Example](#example))
* Implement the Orchestration SDK call that submits the authentication result (see [Android reference](https://transmitsecurity.github.io/ido-android-api-reference/-identity%20-orchestration%20-s-d-k/com.transmit.idosdk/-t-s-ido/submit-client-response.html) or [iOS reference](https://transmitsecurity.github.io/identityOrchestration-ios-sdk-docs/documentation/identityorchestration/tsido/submitclientresponse%28clientresponseoptionid:data:%29))
* Configure the **Mobile PIN Authentication** journey step


Note
For Android, the Authentication SDK requires `compileSdk` 34 (or greater) and `minSdk` 23.

## Configuration

div
| Field | Description |
|  --- | --- |
| **User identifier source** | Specifies the source of the user identifier. It can either be provided by the client (default) or set in the journey. |
| **Identifiers** | Only configured if the user identifier source is provided by the journey step. Can be an external user ID, email, phone number, username, or a [custom identifier](/guides/user/manage_user_schema), if configured for B2C users in your tenant. |
| **Org context** | **Only in B2B journeys**. Determines the organization for which the step is executed. By default, the step uses the org context previously set in the journey (e.g., using [Select organization](/guides/orchestration/journeys/select_organization) step). If set to "manual", you can provide an expression that yields the organization ID. |
| **Error Output Variable** | Name of the variable that stores any errors returned by action |
| **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). |
| **Custom Branches** | Additional journey branches supported for this step. The client can select a branch by returning the branch ID. For each branch, you can define a schema for the information that the client is expected to return (used by the code generator and for autocompleting journey expressions) and a display name to label it in the editor. |
| **Branch Output Variable** | Name of the variable used to store the data returned by the client, which can be used in subsequent journey steps. |
| **Cancel Behavior** | Determines the behavior of client cancellation, which either aborts the journey (default) or proceeds to a cancel branch of the control flow |


## Example

When executed, this step sends a callback to the client with the IDO service response object. It includes a challenge to be signed using the registered PIN credentials. The client prompts the user to enter their app-specific PIN, performs the signing operation using the Authentication SDK, and submits the signed result back to the journey using the Orchestration SDK.

Swift

```swift
private func authenticatePINCode(idoResponse: TSIdoServiceResponse, pinCode: String) {
    // Extract user identifier and challenge from the IDO response
    guard let username = idoResponse.data?["user_identifier"] as? String else {
        debugPrint("[ERROR] User identifier not found in IDO response")
        return
    }

    guard let challenge = idoResponse.data?["pin_challenge"] as? String else {
        debugPrint("[ERROR] Pin challenge not found in IDO response")
        return
    }

    // Authenticate the user using the provided PIN and challenge
    TSAuthentication.shared.authenticatePinCode(username: username, pinCode: pinCode, challenge: challenge) { result in
        switch result {
        case .success(let response):
            do {
                // Build the result payload to send back to the journey
                let data: [String: Any] = [
                    "publicKeyId": response.publicKeyId,
                    "challenge": response.challenge,
                    "signature": response.signature,
                    "userIdentifier": username
                ]

                // Submit the authentication result to the journey
                do {
                    try TSIdo.submitClientResponse(clientResponseOptionId: .clientInput, data: data)
                } catch {
                    debugPrint("[DEBUG] Failed to submit PIN authentication result: \(error)")
                }
            } catch {
                debugPrint("[ERROR] Pin Authentication failed with error: \(error)")
            }
        case .failure(let error):
            // Handle authentication failure
            debugPrint("[ERROR] Pin Authentication failed with error: \(error)")
        }
    }
}
```

Kotlin

```kotlin
// Data model for the authentication result to send back to the journey
data class PinCodeAuthenticationInput(
    @SerializedName("publicKeyId") val publicKeyId: String,
    @SerializedName("signature") val signature: String,
    @SerializedName("userIdentifier") val userIdentifier: String
)

fun authenticatePinCode(idoResponse: TSIdoServiceResponse, pinCode: String) {
    // Extract user identifier and challenge from the IDO response
    val userId = idoResponse.responseData?.optString("user_identifier")
    val challenge = idoResponse.responseData?.optString("pin_challenge")

    // Authenticate the user using the provided PIN and challenge
    TSAuthentication.authenticatePinCode(userId, pinCode, challenge, object : TSAuthCallback<TSPinCodeAuthenticationResult, TSPinCodeAuthenticationError> {
        override fun error(error: TSPinCodeAuthenticationError) {
            // Handle authentication failure
            when (error) {
                is TSPinCodeAuthenticationError.NotRegistered -> {
                    showError("Pin code authenticator is not registered")
                }
                is TSPinCodeAuthenticationError.InternalError -> {
                    showError("Internal error " + error.errorMessage)
                }
            }
        }

        override fun success(result: TSPinCodeAuthenticationResult) {
            // Build the result payload to send back to the journey
            TSIdo.submitClientResponse(
                TSIdoClientResponseOptionType.ClientInput.type,
                PinCodeAuthenticationInput(
                    result.keyId(),
                    result.signature(),
                    userId
                ),
                callback
            )
        }
    })
}
```