Email OTP Authentication

Authenticates the user using a one-time code (OTP) sent by email

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 sends a one-time code (OTP) to the user's email, and then validates the code to authenticate the user. For example, it can be used to validate the user's email, authenticate the user in recovery flows, or as a second-factor for authentication.

This step requires the email to send the code to, and the user identifier if it's different than the email. If the email is the user identifier, it can be simply obtained using a login form (see Login Form). If different, the journey must also ensure that the email indeed corresponds to the authenticating user. For example, if a form collects both the identifier and email, the journey should check that it's a known email for this user. Or if the form collects only the identifier, the journey can use it to look up the email from a trusted source.

Once initiated, this step sends an OTP to the specified email and then asks the client to send it back to the journey. The client retrieves the code from the user and submits it to the journey for validation. If successful, the journey sets the user context to the authenticated user and continues to the next step. Tokens generated for the authentication can be accessed in subsequent steps using @policy.userTokens().

When building your authentication solution, you'll need to consider how to handle the different error cases. If the user didn't receive the code, the client can ask the journey to resend it (using a Resend response). If the user submits an invalid code, the journey will ask the client to resubmit the code (errorData will contain the error). And if the step fails, the journey proceeds to a failure branch (if specified); otherwise, the journey is aborted and an error is sent to the client.

Email formatting options allow you to customize the content of the email sent with the OTP code, including the subject, header, body text, footer, and logo. While these settings are defined in the OTP settings of the Admin Portal, any configurations applied within the step will override the Admin Portal settings when the email is generated and sent by Mosaic's backend. You can also edit security features such as code length, expiration, and failure lockout rules to tailor the user experience further.

Configuration

Field Description
External User ID User identifier, specified as an expression. Only configured if the journey doesn't authenticate the user before invoking this step. Note that, if the identifier doesn’t exist, a Mosaic user record is automatically created.
Email Email to send the code to, specified using an expression.
Recipient Selection Strategy Defines how recipients are chosen from the list resolved by the Recipients expression (if it resolves to multiple email addresses). Default is First Successful Recipient. Options:
  • All Recipients: Sends the email to all recipients.
  • First Successful Recipient: Sends the email to the first recipient it successfully reaches (e.g., if sending to the first recipient fails, it tries the next one).
Recipients An expression that resolves to one or more email addresses, provided as a string or an array of strings.
Enable custom content Allows customization of the email's content and appearance.
Subject (Available if Enable custom content is enabled) Subject of the email. Supports interpolated strings for dynamic subjects. Default: “Login using a one-time code”.
Sender name (Available if Enable custom content is enabled) The displayed name of the sender, replacing the plain email address. Supports interpolated strings. Default: your Mosaic app name.
Logo (Available if Enable custom content is enabled) Base64-encoded JPEG, PNG, or WEBP logo displayed at the top of the email. Limited to 20,000 characters. Default: none.
Header text (Available if Enable custom content is enabled) Text displayed as the email header. Supports interpolated strings. Default: “Let’s log you in”.
Body text (Available if Enable custom content is enabled) The main content of the email body, shown above the OTP code. Default: “This code will securely log you in. Do not share this code with other people.”. Supports interpolated strings.
Info text (Available if Enable custom content is enabled) Additional information text displayed below the OTP code. Supports interpolated strings. Default: “This code will expire in a few minutes.”.
Footer text (Available if Enable custom content is enabled) Text displayed at the bottom of the email. Supports interpolated strings. Default: “If you did not request this email, you can safely ignore it.”.
Error Output Variable Name of the variable that stores any errors returned by 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).
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 when a custom branch is selected, 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 1: Email OTP validation

Suppose a login form is used to collect the user's email, which is also the user identifier in our example. The form ID is loginForm, the input will be stored in a variable named loginData, and only Email OTP is enabled. The OTP branch has the default branch ID (email_otp) and schema is updated to expect only email (email).

The authentication step obtains the email from the form output (loginData.email):

When executed, this step sends an OTP to the specified email and then instructs the client to send it back once the user inputs it. The idoServiceResponse object will include the journeyStepId as EmailOTPAuthentication and the length of the code in the data. For example:

Copy
Copied
{
 "data": {
   "code_length": <integer_code_length>
  }
}

Once the client obtains the code, it submits it back to the journey to complete the authentication. For example:

JavaScriptKotlinSwift
Copy
Copied
// Submits the OTP entered by the user
 window.tsPlatform.ido.submitClientResponse(
     ClientResponseOptionType.ClientInput,
     {
         "passcode": "<passcode>"
     })
Copy
Copied
  data class OtpResult(val passcode: String)

  // ...

  val responseData = OtpResult(collectedOTP)
  
  // Submits the OTP entered by the user
  TSIdo.submitClientResponse(
      TSIdoClientResponseOptionType.ClientInput.type, 
      responseData, 
      callback
      )
Copy
Copied
  // Submits the OTP entered by the user
  TSIdo.submitClientResponse(
    clientResponseOptionId: .clientInput, 
    data: ["passcode": "[passcode]"]
    )

In case the client has a button for resending the OTP code, it can submit a resend request to the journey. For example:

JavaScriptKotlinSwift
Copy
Copied
// Request resend clicked by the user
 window.tsPlatform.ido.submitClientResponse(ClientResponseOptionType.Resend)
Copy
Copied
  // Request resend clicked by the user
  TSIdo.submitClientResponse(
    TSIdoClientResponseOptionType.Resend.type, 
    null, 
    callback
    )
Copy
Copied
  // Request resend clicked by the user
  TSIdo.submitClientResponse(clientResponseOptionId: .resend)

Example 2: Customizing email formatting

In this example, we configure the Email OTP Authentication step to send a customized email with a branded subject line, logo, and personalized text. The following settings are applied in the step's configuration:

condition example

When the step executes, the email sent to the user will look like this: