Asking a user to provide OTP is that sent via SMS is common practice on web in several case related to user account access to secure several user account related activities by user. Here are few use cases for SMS OTP:

Two Step Authentication: Asking for OTP in addition to user name and password provide additional security in user account authentication.

Phone number verification: There are many services who use a phone number as the user’s primary identifier. In such services, users can enter their phone number and OTP received with SMS to authenticate themselves. Sometimes it’s combined with a PIN to constitute a two-step authentication.

Phone Number Verification: Some services use a phone number as the user’s primary identifier. In such services, users can enter their phone number and the OTP received via SMS to prove their identity. Sometimes it’s combined with a PIN to constitute a two-factor authentication.

Account Recovery: When a user loses access to his account, there needs a way to recover it. Common ways to recover account access is to send an email on users registered email or an SMS OTP to their phone number are common account recovery methods.

Payment confirmation: In payment systems, many banks or credit card issuers commonly use SMS OTP authentication from the payer for security reasons.

Here we are explaining best practices to create an SMS OTP for the above use cases.

Checklist

To provide the best user experience with the SMS OTP, follow these steps:

To make the SMS OTP form most user friendly, follow these steps:

  • Use the <input> element with:
    • type=”text”
    • inputmode=”numeric”
    • autocomplete=”one-time-code”
  • Use @BOUND_DOMAIN #OTP_CODE as the last line of the OTP SMS message.
  • Use the Web OTP API.

Use the <input> element 

Using a form with an <input> element is the most important best practice you can follow because it is supported in all browsers. Even if other suggestions from this post don’t work in some browser, the user will still be able to enter and submit the OTP manually.

<form action="/verify-otp" method="POST">
  <input type="text"
         inputmode="numeric"
         autocomplete="one-time-code"
         pattern="\d{6}"
         required>
</form>

To get best out of your browser functionality use following ideas:

Using type=”text”

Since OTPs are usually five or six digit numbers, using type=”number” for an input field might seem more logical because it changes the mobile keyboard to numbers only. This is not recommended because the browser expects an input field to be a countable number rather than a sequence of multiple numbers, which can cause unexpected behavior.

Using type=”number” causes up and down buttons to be displayed with the input field and pressing these buttons increments or decrements the number and may remove preceding zeros.

Use type=”text” instead. This won’t turn the mobile keyboard into numbers only, You can do that using the next tip for using inputmode=”numeric” does that job. but that is fine because the next tip for using inputmode=”numeric” does that job.

Add inputmode=”numeric”

Using inputmode=”numeric” will change the mobile keyboard to numbers only. Avoid using the semantically incorrect type=”tel” hack. This hack was used in the past when inputmode=”numeric” wasn’t widely supported.

autocomplete=”one-time-code”

With autocomplete attribute developers can specify what permission the browser has to provide autocomplete assistance and informs the browser about the type of information expected in the input field.

With autocomplete=”one-time-code” whenever a user receives an SMS message while a form is open, the operating system will parse the OTP in the SMS heuristically and the keyboard will suggest the OTP for the user to enter.

Currently it works only on Safari 12 and later on iOS, iPadOS, and macOS, but we strongly recommend using it, because it is an simple way to improve the SMS OTP experience for users on those platforms.

OTP verification process

autocomplete=”one-time-code” improves the user experience, but there’s more you can do by

Format the SMS text

Enhance the user experience of entering an OTP by aligning with the origin-bound one-time codes delivered via SMS specification.

Just follow this simple format rule: End the SMS message with the receiver domain name preceded with @ and the OTP preceded with #.

For example:

Your OTP is 123456

@web-otp.glitch.me #123456

Using a standard format for OTP messages makes extraction of codes from them easier and more reliable. When you Associate OTP codes with websites it becomes harder for malicious sites to trick users into providing a code to them.

Following are the price rule:

  • The message should begin with (optional) human-readable text that containing a four to ten characters alphanumeric string with at least one number, last line should be left for the URL and the OTP.
  • The domain part of the websites URL that invoked the API must be preceded by @.
  • The URL must contain a pound sign (“#”) followed by the OTP.
  • Number of Characters in the message should not exceed 140 in total.

Using this format provides a couple of benefits:

  • The OTP in SMS will be bound to the domain name. If the user is on domains other than the one specified in the SMS message, the OTP suggestion won’t appear. This also reduce the risk of phishing attacks and potential account hijacks.
  • Browser will get to extract the OTP in much more reliable way Browser will now be able to reliably extract the OTP without following mysterious and unconventional heuristics.

When a website uses autocomplete=”one-time-code”, Safari with iOS 14 or later will suggest the OTP following the above rules.

This OTP SMS message format also benefits browsers other than Safari. Chrome, Opera, and Vivaldi on Android also support the origin-bound one-time codes rule with the Web OTP API, though not through autocomplete=”one-time-code”.