# Login with TOTP

Mosaic allows authenticating users with [time-based one-time passcodes (TOTP)](https://datatracker.ietf.org/doc/html/rfc6238) which are unique one-off numeric codes generated by authenticator apps (Google Authenticator, Microsoft Authenticator, Twilio Authy, and others). The passcodes are short-lived and typically change every 30 seconds making the TOTP authentication hard to compromise.

You can leverage TOTP as a stand-alone passwordless authentication solution, but it's mainly used as a second factor in MFA or with user actions that affect sensitive resources, such as their payment data or personal records, and require an additional layer of security.

Note
This guide explains how to implement TOTP authentication using [Journeys](/guides/journeys_intro) and SDKs.

## How it works

The TOTP authentication relies on the static secret (seed) and passcode validity. To use the TOTP for the first time, one has to register the TOTP authenticator with Mosaic and connect it to an authenticator app. Mosaic uses the TOTP authenticator to validate codes that are generated by the authenticator app. Depending on the app settings, a user can register one authenticator per application or multiple authenticators. Once set, a user can proceed to log in using time-based passcodes generated by the authenticator app.

### Registration

The client invokes a journey that prompts the user to provide their user identifier (alternatively, to log in) and specify a meaningful label for the TOTP authenticator.
Upon reaching the Register TOTP step, Mosaic checks the number of active TOTPs per user and, if possible, proceeds to registration.

Single vs multiple TOTPs
Depending on your app settings, Mosaic applies custom logic to registering new TOTPs:

**Single-TOTP configuration**

- Registers a TOTP unless a user has another active TOTP.
- If there is a TOTP associated with the user, Mosaic can either block registration or override the existing TOTP (as configured in the Register TOTP step).


**Multiple-TOTP configuration**

- Registers a new TOTP as long as the user has not reached the limit.
- Once the limit is reached, Mosaic will block registration of new TOTPs.


Mosaic generates and returns the static secret that will be used to generate TOTP codes for authentication. The app then provides the secret to the user, for example, by displaying the returned `uri` as a QR code. The user scans the QR code using their authenticator app, and indicates to your app once they're done.

```mermaid
sequenceDiagram
  participant U as User
  participant C as Client
  participant IDO as Orchestration SDK
  participant A as Authenticator app

U -->> C: Register TOTP
C ->> IDO: startJourney()
note left of IDO: Register TOTP
IDO -->> IDO: Check active TOTPs
opt Block registration
  IDO ->> C: Can't register TOTP
end
opt Proceed with registration
  IDO ->> C: Return `uri`
  C -->> U: Display QR code
  U -->> A: Scan QR code
  A -->> A: Set up authenticator
  A -->> U: Complete
  U -->> C: Done
  C ->> IDO: Done
  C -->> U: TOTP registered
end
```

### Authentication

As part of the login journey, Mosaic prompts a user to input a passcode generated by the authenticator app. Once the code is received, Mosaic validates it against all active TOTPs. If successful, the journey completes and the user is set as authenticated.

```mermaid
sequenceDiagram
  participant U as User
  participant C as Client
  participant IDO as Orchestration SDK
  participant A as Authenticator app

U -->> C: Log in
C ->> IDO: startJourney()
note left of IDO: Login form
IDO ->> C: Waiting for user identifier and passcode
C -->> U: Collect user identifier and passcode
U -->> A: Get passcode
A -->> U: Display passcode
U -->> C: Enter passcode and user identifier
C ->> IDO: user identifier and passcode
note left of IDO: Auth TOTP
IDO ->> IDO: Validate passcode against <br> all active TOTPs for the user
IDO ->> C: User logged in
C -->> U: Logged in
```

## Before you start

1. If this is your first time integrating with Mosaic, create an application in the Admin Portal as described [here](/guides/user/create_new_application/).
2. The flow assumes that the user already exists in Mosaic. Add a new user if necessary.
3. The flow assumes that the user has already downloaded an authenticator app (Google Authenticator, Microsoft Authenticator, Twilio Authy, and others) on their mobile device and created an account. To build a custom authenticator app, see [Custom TOTP generator (iOS)](/guides/user/be_auth_totp_authenticator_ios) and [Custom TOTP generator (Android)](/guides/user/be_auth_totp_authenticator_android).


## Step 1: Configure authenticator

div
div
Admin Portal
By default, the passcode includes 6 digits and changes every 30 seconds. The authenticator settings (**Admin Portal** > **B2C Identity** or **B2B Identity** > app > **Authentication methods**) allow you to:

- adjust the passcode behavior
- define the maximum number of TOTP authenticators allowed per user
- configure the lockout policy in case of repeated failed attempts (see [Lockout policies](/guides/user/auth_lockout_policies))


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

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

## Step 2: Build 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 the registration journey and one for the authentication journey.

### Registration journey

This client SDK journey collects any required user information and registers a TOTP authenticator for the user, so they can use TOTP codes for future authentication flows. It can include the following actions:

1. Collects information from the user ([Collect information](/guides/orchestration/journeys/get_info_from_client) step), including a user identifier and a label to distinguish TOTPs later. These inputs are stored in the output variable to be used in the next step. Alternatively, authenticate the user first using any other authentication method.
2. Registers a TOTP authenticator for the user ([Register TOTP](/guides/orchestration/journeys/register_totp) step). This step uses the user identifier collected in a previous step.


Single‑TOTP behavior
Configure **single‑TOTP behavior** if the app allows only **one TOTP per user**—either override the existing authenticator or block registration and proceed to the failure branch. If your app allows multiple TOTPs per user, this setting is irrelevant. For more details about registration logic, see [How it works: registration](#registration).

1. Depending on results, successfully completes the journey ([Complete journey](/guides/orchestration/journeys/complete_journey) step) or rejects access ([Reject access](/guides/orchestration/journeys/reject_access) step).


figure
a
img
figcaption
Click to open the image in a dedicated tab.
### Authentication journey

This client SDK journey logs in the user using a TOTP code generated by their authenticator app. It can include the following actions:

1. Displays a login form with an enabled TOTP authentication option ([Login form](/guides/orchestration/journeys/login_form) step). Obtains input from the user (username and passcode), which is then saved in the output variable.
2. Authenticates the user using the TOTP code ([TOTP Authentication](/guides/orchestration/journeys/authenticate_totp) step) obtained in a previous step. If successful, this step sets the user context.
3. Depending on results, successfully completes the journey ([Complete journey](/guides/orchestration/journeys/complete_journey) step) or rejects access ([Reject access](/guides/orchestration/journeys/reject_access) step).


figure
a
img
figcaption
Click to open the image in a dedicated tab.
## Step 3: Add SDKs

div
div
client
To run this flow, your integration needs the Orchestration SDK.

- Installation: [Web](/sdk-ref/idosdk/overview/#installation), [Android](/guides/orchestration/getting-started/quick_start_android/#step-1-load-sdk), [iOS](/guides/orchestration/getting-started/quick_start_ios/#step-1-load-sdk)
- Initialization: [Web](/sdk-ref/idosdk/overview/#initialization), [Android](/guides/orchestration/getting-started/quick_start_android/#step-2-initialize-sdk), [iOS](/guides/orchestration/getting-started/quick_start_ios/#step-2-initialize-sdk)


## Step 4: Implement journey logic

div
div
client
Implement the client-side code needed to complete your journeys on the device. In a nutshell, you have to implement:

- [Starting the journey](#1-starting-the-journey)
- [Collecting information](#2-collecting-information)
- [Registering TOTP](#3-registering-totp)
- [Login form](#4-login-form)


Implementation tips
For example, implement a switch (or other routing mechanism) that invokes a handler responsible for a specific journey step (returned in `idoServiceResponse.journeyStepId` parameter). Each handler processes data, displays whatever UI is needed, and calls `submitClientResponse()` when the interaction is concluded.

The journey loops back to the switch unless Mosaic signals journey completion by setting the `journeyStepId` property to `Rejection.type` or `Success.type`. The `idoServiceResponse.token` property contains a JWT token as a proof of journey completion.

For more guidance on mobile development with the Orchestration SDK, refer to these quickstarts: [Web](/guides/orchestration/getting-started/quick_start_web), [Android](/guides/orchestration/getting-started/quick_start_android/) or [iOS](/guides/orchestration/getting-started/quick_start_ios/).

### 1. Starting the journey

Implement a handler that starts the journey. Use the following call to start the journey:

```js
// If SDK was loaded via script tag, invoke functions inside 'window.tsPlatform'
const idoResponse = await ido.startJourney(
      'YOUR_JOURNEY'
  );
```

```swift
TSIdo.startJourney(journeyId: "YOUR_JOURNEY_ID")
```

```kotlin
TSIdo.startJourney("YOUR_JOURNEY_ID", startJourneyOptions, callback)
```

### 2. Collecting information

Implement obtaining user's email as identifier and label for authenticator. This handler is invoked when the `idoServiceResponse` object includes `journeyStepId` matching the ID of the Collect Information step (e.g., `get_info_from_client_1`).

For example, your application should present a form that collects a user email and TOTP label and pass them to the Orchestration SDK. For more details, see [Collect information](/guides/orchestration/journeys/get_info_from_client).

### 3. Registering TOTP

Implement registering a TOTP authenticator. This handler is invoked when the `idoServiceResponse` object includes `journeyStepId` set to [TotpRegistration](/sdk-ref/idosdk/enums/idojourneyactiontype#totpregistration). It should embed the `uri` returned by the Orchestration SDK in a QR code for the user to scan with their mobile app. Once completed, it sends an empty response to the journey.

Important
The authenticator registration is considered complete as soon as a secret is created. If the user chooses not to set up an authenticator app at this time, the secret will remain associated with this user anyway.

JavaScript
```js
    // If SDK was loaded via script tag, invoke functions inside 'window.tsPlatform'
    ido.submitClientResponse(
        ClientResponseOptionType.ClientInput
    )
```

Kotlin
```kotlin
// If you're using a custom authenticator app built with the Mosaic Authentication SDK,
// register the secret first using registerTOTP() before submitting.
TSIdo.submitClientResponse(
    TSIdoClientResponseOptionType.ClientInput.type,
    null,
    callback
)
```

Swift
```swift
// If you're using a custom authenticator app built with the Mosaic Authentication SDK,
// register the secret first using registerTOTP() before submitting.
TSIdo.submitClientResponse(
    clientResponseOptionId: .clientInput,
    data: data
)
```

### 4. Login form

Implement obtaining a user's identifier and passcode. This handler is invoked when the `idoServiceResponse` object includes `journeyStepId` matching the ID of the Login Form step (e.g., `authentication`).

For example, your application should present a form that collects a user email and passcode and pass them to the Orchestration SDK. For more details, see [Login Form](/guides/orchestration/journeys/login_form).

## Next steps

- Update your journeys to use TOTP as a second factor in MFA flows.
- Consider implementing fallback authentication methods for users who lose access to their authenticator app.
- Implement the ability to revoke TOTP registrations. This capability is necessary when the user has reached the TOTP limit and new registrations are blocked. Let users choose the authenticator to deregister. First implement the "User Authenticators: User authenticators API" step to locate available authenticators, then let the user choose the one to revoke by its label, for example, using a form. Then use the [Revoke my TOTP](/guides/orchestration/journeys/revoke_my_totp) step to deregister a TOTP authenticator.
- Implement transaction signing with TOTP by swapping the [TOTP Authentication](/guides/orchestration/journeys/authenticate_totp) with the [Transaction signing with TOTP](/guides/orchestration/journeys/transaction_signing_totp) step. Pass along the transaction details for the user to approve. The approval data is a JSON object, its fields may include expressions.


```Json
{
  "data": {
    "transaction_challenge": "123456",
    "approval_data": {
      "transactionId": "TX12345",
      "amount": "1500.00",
      "currency": "USD"
    }
  }
}
```