# Login with PIN

PIN authentication lets users authenticate using a PIN code defined on their device. This PIN unlocks a locally stored encrypted seed, from which a secure key pair is derived on demand. The private key is used to sign authentication challenges, while the PIN and private key never leave the device. This ensures a user-friendly yet secure experience based on strong cryptography. For more about the PIN authenticator's settings for behavior and lockout policies, see our [Manage authenticators](/guides/user/auth_methods_customize) page.

Note
This guide explains how to implement authentication with PIN codes using [Journeys](/guides/journeys_intro) and mobile Orchestration SDKs. To learn more about SDKs integration, see [Orchestration quickstart (Android)](/guides/orchestration/getting-started/quick_start_android) and [Orchestration quickstart (iOS)](/guides/orchestration/getting-started/quick_start_ios).

## How it works

Mobile PIN authentication is based on asymmetric cryptography. When the user registers a PIN, the **Authentication SDK** generates a random secret seed, which is encrypted using the PIN and securely stored on the device. The PIN itself is never stored, and the private key is never persisted — it only exists in memory when needed.

### PIN registration

During registration, the **Orchestration SDK** receives a `registerPinCode` step from Mosaic and exposes it to the app. The app prompts the user to enter a PIN and then calls the **Authentication SDK**, which encrypts the seed and derives a public/private key pair. The public key and its identifier are returned to the app, which submits them to Mosaic via the Orchestration SDK.

Mosaic then returns a `PinCodeRegistrationCommit` instruction to finalize the process. The Orchestration SDK exposes this instruction to the app, which must call `commitPinCodeRegistration()` using the Authentication SDK. This marks the key as ready for use in authentication.


```mermaid
sequenceDiagram
    participant User
    participant App as Client App
    participant OrchestrationSDK as Orchestration SDK
    participant M as Mosaic Server
    participant AuthSDK as Authentication SDK

    User-->>App: Launch app
    App-->>OrchestrationSDK: Start registration journey
    OrchestrationSDK->>M: Request journey
    M->>OrchestrationSDK: Return registerPinCode step
    OrchestrationSDK->>App: Expose registerPinCode step
    App->>User: Prompt for PIN
    User-->>App: Enter PIN
    App->>AuthSDK: Call registerPinCode(PIN)
    AuthSDK->>App: Return public key, key ID
    App->>OrchestrationSDK: Submit public key, key ID
    OrchestrationSDK->>M: Submit result
    M->>OrchestrationSDK: Return PinCodeRegistrationCommit instruction
    OrchestrationSDK->>App: Expose commit instruction
    App->>AuthSDK: Call commitPinCodeRegistration()
    AuthSDK->>App: Return success
    App->>User: Confirm registration
```

### PIN authentication

During authentication, the **Orchestration SDK** receives a `authenticatePinCode` step from Mosaic and exposes it to the app. The app collects the user's PIN and invokes the **Authentication SDK**, which decrypts the seed, derives the key pair on demand, and signs a challenge received from Mosaic. The signed result is sent back through the Orchestration SDK to Mosaic, where it is verified using the public key.


```mermaid
sequenceDiagram
    participant User
    participant App as Client App
    participant AuthSDK as Authentication SDK
    participant OrchestrationSDK as Orchestration SDK
    participant M as Mosaic Server

    User-->>App: Launch app
    App->>OrchestrationSDK: Start authentication journey
    OrchestrationSDK->>M: Request journey
    M->>OrchestrationSDK: Return authenticatePinCode step
    OrchestrationSDK->>App: Expose authenticatePinCode step
    App->>User: Prompt for PIN
    User-->>App: Enter PIN
    App->>AuthSDK: Call authenticatePinCode(PIN)
    AuthSDK->>App: Return signed challenge
    App->>OrchestrationSDK: Submit signed challenge
    OrchestrationSDK->>M: Submit result
    M->>OrchestrationSDK: Authentication successful
    OrchestrationSDK->>App: Notify success
    App-->>User: Logged in
```

## Requirements

details
summary
b
iOS
**iOS**

- iOS 13+
- Xcode 11+


details
summary
b
Android
**Android**

- Android 5+ (API level 21+)


## Before you start

Before you start, make sure you have a Mosaic application with an OIDC client. See [create an application](/guides/user/create_new_application).

For a user to register a PIN, they must already exist in your app and verify their identity before registration. This authentication can be performed using any supported method (e.g., password, OTP, document verification), either within the same journey or in a prior one.

## Step 1: Configure PIN authenticator

div
div
Admin Portal
Mobile PIN authentication lets users log in to their app using a PIN code that they choose specifically for the app. The PIN format and complexity (e.g., 4 or 6 digits) are defined by your application and must be enforced in the frontend.

The PIN authentication settings (**Admin Portal** > **B2C Identity** or **B2B Identity** > **Authentication methods** ) allow you to configure the lockout policy in case of repeated failed attempts:

- **Failed attempts**: set the number of incorrect PIN entries allowed before triggering a lockout.
- **Lockout duration**: define how long the user must wait before they can try again.


Tip
Once you've configured the lockout policy, you may also implement logic to unlock the PIN authenticator in case it locks. Use the [Unlock authenticators API](/openapi/user/authenticators.openapi/other/unlockuserauthenticator) to reset a locked PIN code.

For more about the PIN authenticator, see [Customize login methods](/guides/user/auth_methods_customize).

## Step 2: Create journeys

div
div
Admin Portal
In the Admin Portal, go to **B2C Identity** or **B2B Identity** based on your setup, and open the **Journeys** section. Create two separate journeys—one for PIN registration and one for PIN authentication. You can name them as you like, for example `register-pin-journey`, `login-with-pin-journey`.

### PIN registration journey

After adding the following steps to your journey:

1. [Login form](/guides/orchestration/journeys/login_form)
2. [Authenticate with password](/guides/orchestration/journeys/authenticate_password)
3. [Register Mobile PIN](/guides/orchestration/journeys/register_mobile_pin)


Configure them as follows:

#### Login form

Configure this step to display a form that collects a password. Basic configuration for our example includes:

- **Authentication methods**: Enable only **Password**.
- **Step ID**: Provide a unique identifier, e.g., `loginForm`. This is used by the client to recognize the step.
- **Branch output variable**: Set to `loginData`. This is the variable that stores the user input and passes it to the next step.


#### Authenticate with password

Configure this step to validate the user credentials collected in the previous step. Basic configuration for our example includes:

- **External user ID**: Set to `loginData.username`. This maps the value submitted via the login form.
- **Password**: Set to `loginData.password`. This retrieves the password submitted by the user.


#### Register Mobile PIN

This step binds the PIN credential to the device. Basic configuration for our example includes:

- **User Auth State**: Leave set to `The user is authenticated`.
- **Branch Output Variable**: Set to `pinRegistrationData` or similar. This stores the result returned by the client (e.g., public key info).


### PIN authentication journey

After adding the following steps:

1. [Login form](/guides/orchestration/journeys/login_form)
2. [Authenticate with Mobile PIN](/guides/orchestration/journeys/authenticate_mobile_pin)


Configure them as follows:

#### Login form

Configure this step to display a form that collects a PIN code. Basic configuration for our example includes:

- **Authentication methods**: Enable only **Mobile PIN**.
- **Step ID**: Provide a unique identifier, e.g., `loginForm`.
- **Branch output variable**: Set to `loginData`. This variable will hold the PIN input sent by the client.


Note
You can extend this journey later by enabling additional authentication methods (e.g., password or OTP) to support fallback scenarios.

#### Authenticate with Mobile PIN

This step verifies the user using the registered PIN. Basic configuration for our example includes:

- **User identifier source**: Set to `Provided by the client`.
- **Branch output variable**: Set to `pinAuthData` or similar. This variable will contain the signed result submitted by the client.


## Step 3: Add mobile SDKs

div
div
mobile client
To run this flow, your integration needs the Orchestration SDK (for [iOS](https://transmitsecurity.github.io/identityOrchestration-ios-sdk-docs/documentation/identityorchestration/) and [Android](https://transmitsecurity.github.io/ido-android-api-reference/index.html)) and Authentication SDK (for [iOS](https://transmitsecurity.github.io/authentication-ios-sdk-docs/documentation/tsauthenticationsdk/) and [Android](https://transmitsecurity.github.io/authentication-android-docs/)) to enable your application to use mobile biometrics and invoke journeys.

Important
Make sure to initialize mobile SDKs within the context of the same client ID.

For Android, see instructions here:

- Adding to project: [Orchestration SDK](/guides/orchestration/sdk/android_sdk_guide/#step-1-installation) and [Authentication SDK](/guides/user/be_auth_biometrics_android/#step-1-add-sdk-to-your-project)
- Initializing: [Orchestration SDK](/guides/orchestration/sdk/android_sdk_guide/#step-2-initialize-sdk) and [Authentication SDK](/guides/user/be_auth_biometrics_android/#step-2-initialize-the-sdk)


For iOS, see instructions here:

- Loading: [Orchestration SDK](/guides/orchestration/sdk/ios_sdk_guide/#step-1-installation) and [Authentication SDK](/guides/user/be_auth_biometrics_ios/#step-1-add-sdk-to-your-project)
- Initializing: [Orchestration SDK](/guides/orchestration/sdk/ios_sdk_guide/#step-2-initialize-sdk) and [Authentication SDK](/guides/user/be_auth_biometrics_ios/#step-2-initialize-the-sdk)


## Step 4: Start the journey

div
div
mobile client
You must start the appropriate journey from your mobile app depending on the context, using the journey IDs you defined earlier [step 2](#step-2-create-journeys).

### Launch PIN registration journey

To let a user set up their PIN for the first time, launch the **registration journey** you created (e.g., after successful authentication):

Swift

```swift
// Start the journey to register a PIN
do {
    try TSIdo.startJourney(journeyId: "register-pin-journey")
} catch {
    debugPrint("[DEBUG] Failed to start journey: \(error)")
}
```

Kotlin

```kotlin
// Start the journey to register a PIN
TSIdo.startJourney(
    "register-pin-journey", // Replace with your journey ID
    TSIdoStartJourneyOptions(additionalParams, flowId),
    idoCallback
)
```

Once the journey starts, the client receives a `TSIdoServiceResponse` containing the input required for the step—such as the PIN challenge and user identifier. After submitting the result using `submitClientResponse`, the journey may return a backend instruction (e.g., `PinCodeRegistrationCommit`) that must be handled to complete the operation. Make sure your implementation is prepared to handle this instruction by committing the registration result using the SDK.

### Launch PIN authentication journey

To authenticate the user using their PIN, launch the **authentication journey**:

Swift

```swift
// Start the journey to authenticate with PIN
do {
    try TSIdo.startJourney(journeyId: "login-with-pin-journey")
} catch {
    debugPrint("[DEBUG] Failed to start journey: \(error)")
}
```

Kotlin

```kotlin
// Start the journey to authenticate with PIN
TSIdo.startJourney(
    "login-with-pin-journey", // Replace with your journey ID
    TSIdoStartJourneyOptions(additionalParams, flowId),
    idoCallback
)
```

Once the journey starts, the client receives a `TSIdoServiceResponse` containing the input required for the step—such as the PIN challenge and user identifier. After generating the signed result using the Authentication SDK, submit it back using `submitClientResponse`. No additional backend instruction is expected in this case.

Note
In Android, the `idoCallback` object must implement the `TSIdoCallback` interface to receive the journey result.

style

    section article ol li {
        margin-top: 6px !important;
    }

    th {
      min-width: 155px;
    }