Validate phone number

Validates a phone number using a one-time code (OTP) sent by SMS

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 a phone number via SMS, then validates the code to verify the phone number. Note that this step is used in contexts where no user is authenticated, such as when the user needs to recover their credentials before logging in.

This step requires the phone number to send the code to. Once initiated, this step sends an OTP to the specified phone number 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, proving the user have access to the indicated phone number.

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.

The OTP settings for your application include security features like code length, expiration, and failure lockout rules.

Configuration

Field Description
Phone Expression field to receive a variable representing the phone number.
Code length Sets the length of the one-time code between 4 and 8 digits. The default is 6.
Expiry in minutes Sets the OTP expiration period between 1 and 15 minutes. The default is 3 minutes.
Max failed attempts Sets the number of failed login attempts that trigger a temporary user lockout and specify the lockout duration in minutes. Can be set between 1 and 5 attempts. The default is 3. After reaching the limit, it fails with max_attempts_reached.

Example

Suppose a journey involves verifying that the client has access to a specified phone number. This could be for first-time registration or for adding a secondary phone number to their profile. The Get Information from Clientstep is used to collect the user’s phone number. The form ID is getphoneForm, the input will be stored in a variable named getphoneData. The phone validation branch has the default branch ID (sms_otp) and schema is updated to expect only email (phone).

The authentication step obtains the phone number from the form output (getphoneData.phone):

Description of the image
Click to open the image in a dedicated tab.

When executed, this step sends an OTP to the specified phone number and then instructs the client to send it back once the user inputs it. This action helps prove the phone number without creating or affecting any user record. The idoServiceResponse object will include the journeyStepId as SmsOTPAuthentication 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)

If validation is successful, it can be followed up with a Register Phone action.