Skip to content
Permalink
Fetching contributors…
Cannot retrieve contributors at this time
398 lines (317 sloc) 13.8 KB
title subhead authors date hero alt description tags
Verify phone numbers on the web with the SMS Receiver API
Help users type OTPs received through SMS
agektmr
2019-10-07
hero.png
A drawing of a woman using OTP to log in to a web app.
Finding, memorizing, and typing OTPs sent via SMS is cumbersome. The SMS Receiver API simplifies the OTP workflow for users.
post
identity
sms
fugu

What is the SMS Receiver API?

These days, most people in the world own a mobile device and developers are commonly using phone numbers as an identifier for users of their services.

There are a variety of ways to verify phone numbers, but a randomly generated one-time password (OTP) sent by SMS to the number is one of the most common. Sending this code back to the developer's server demonstrates control of the phone number.

This idea is already deployed in many scenarios to achieve:

  • Phone number as an identifier for the user. When signing up for a new service, some websites ask for a phone number instead of an email address and use it as an account identifier.
  • Two step verification. When signing in, a website asks for a one-time code sent via SMS on top of a password or other knowledge factor for extra security.
  • Payment confirmation. When a user is making a payment, asking for a one-time code sent via SMS can help verify the person's intent.

The current process creates friction for the user. Finding an OTP within an SMS message, then copying and pasting it to the form is cumbersome, lowering conversion rates in critical user journeys. Easing this has been a long standing request for the web from many of the largest global developers. Android has an API that does exactly this. So does iOS and Safari.

The SMS Receiver API lets your app receive specially-formatted messages bound to your app's origin. From this, you can programmatically obtain an OTP from an SMS message and verify a phone number for the user more easily. Sign up for the Origin Trial now if you are interested!

{% Aside 'warning' %} Attackers can spoof SMS and can hijack a person's phone number. Carriers can also recycle phone numbers to new users after an account was closed. While SMS OTP is useful to verify a phone number for the use cases above, we recommend using additional and stronger forms of authentication (such as multiple factors and WebAuthn) to establish new sessions for these users. {% endAside %}

Current status

The table below explains the current status of the SMS Receiver API.

Step Status
1. Create explainer Complete
2. Create initial draft of specification In Progress
3. Gather feedback and iterate on design In Progress
4. Origin trial Starts in Chrome 78
Expected to run through Chrome 81
5. Launch Not started

See it in action

Let's say a user wants to verify their phone number with a website. The website sends a text message to the user over SMS and the user enters the OTP from the message to verify the ownership of the phone number.

With the SMS Receiver API, these steps will become as easy as one tap for the user, as demonstrated in the video. As the text message arrives, a bottom sheet pops up and prompts the user to verify their phone number. After clicking the Verify button within the bottom sheet, the browser pastes the OTP into the form and the form is submitted without the user needing to press Continue.

The whole process is diagrammed in the image below.

SMS Receiver API diagram Try the demo yourself. It doesn't ask for your phone number or send an SMS to your device, but you can send one from another device by copying the text displayed on the demo. This works because it doesn't matter who the sender is when using the SMS Receiver API.

  1. Prepare Google Chrome on Android 78 or later with the Experimental Web Platform features flag turned on at chrome://flags/#enable-experimental-web-platform-features.
  2. Go to https://sms-receiver-demo.glitch.me.
  3. Select your browser channel from the provided list.
  4. Press Copy to copy the text message and send it to another phone.
  5. Press Verify.
  6. From the other phone, send yourself the copied text message via SMS.

Did you receive the SMS and see the prompt to enter the code to the input area? That is how the SMS Receiver API works for end users.

{% Aside 'warning' %} If you are using a Work Profile on your Android device and the SMS Receiver does not seem to be working, try installing and using Chrome on your personal profile instead (i.e. the same profile in which you receive SMS messages). {% endAside %}

Using the SMS Receiver API

Using the SMS Receiver API consists of two parts: JavaScript code in your web app and the formatted message text sent via SMS.

{% Aside %} The SMS Receiver API requires a secure origin (HTTPS). {% endAside %}

Feature detection

Feature detection is much the same as for many other APIs:

if ('sms' in navigator) {
  ...
}

Process the OTP

The SMS Receiver API itself is simple enough:

const sms = await navigator.sms.receive();

Once a user taps Verify, displayed in the bottom sheet, the promise containing the entire text message will resolve. You can use a regular expression to extract the OTP and verify the user. Notably, you should parse and use the SMS message assuming it could have been altered by an attacker inserting their own SMSes into your app (e.g. following the formatting convention and sending it right after you called navigator.sms.receive()). For example, if a text message contains a six digit verification code following otp=, the code would look like this:

const code = sms.content.match(/^[\s\S]*otp=([0-9]{6})[\s\S]*$/m)[1];

You can now submit the code to the server to verify it.

Formatting the SMS message

The API itself should have looked simple enough, but a critical part is to format your SMS text message according to a specific convention. The message has to be sent after navigator.sms.receive() is called and must comply with a formatting convention.

The SMS message must be received on the device where navigator.sms.receive() was called.

The message must adhere to the following formatting:

  • The origin part of the URL of the website that invoked the API. It must be preceded by For: .
  • The URL must contain (for the time being) a query parameter whose value is the application hash of the user's Chrome instance. (These are static strings. See the table below.)
  • The URL must contain a query parameter otp whose value is the OTP.

An example message that can be retrieved by the browser would look like this:

Your OTP is: 123456.

For: https://sms-receiver-demo.glitch.me/?otp=123456&xFJnfg75+8v

The application hash of Chrome instances are static. Use one of these strings for development depending on which Chrome build you will be working with.

Chrome build APK hash string
Chrome Beta xFJnfg75+8v
Chrome Stable EvsSSj4C6vl

Demos

Try various messages with the demo:
https://sms-receiver-demo.glitch.me

You may also fork it and create your version:
https://glitch.com/edit/#!/sms-receiver-demo.

Enabling support during the origin trial

Starting in Chrome 78, the SMS Receiver API is available as an origin trial on Chrome for Android. Origin trials allow you to try new features and give feedback on their usability, practicality, and effectiveness, both to the Chrome team and to the web standards community. For more information, see the Origin Trials Guide for Web Developers.

To participate in an origin trial:

  1. Request a token for your origin.
  2. Add the token to your pages, there are two ways to provide this token on any page in your origin:
    • Add an origin-trial <meta> tag to the head of any page:
      <meta http-equiv="origin-trial" content="TOKEN_GOES_HERE">
    • If you can configure your server, you can also provide the token on pages using an Origin-Trial HTTP header:
      Origin-Trial: TOKEN_GOES_HERE

Feedback

We want to hear about your experiences with the SMS Receiver API. Please sign up for the Origin Trial now!

Tell us about the API design

Is there something about the API that doesn't work as expected? Or are there missing methods or properties that you need to implement your idea?

Problem with the implementation?

Did you find a bug with Chrome's implementation?

  • File a bug at https://new.crbug.com. Include as much detail as you can, simple instructions for reproducing, and set Components to Blink>SMS.

Planning to use the API?

Planning to use the SMS Receiver API? Your public support helps us prioritize features, and shows other browser vendors how critical it is to support them.

  • Be sure you have signed up for the SMS Receiver Origin Trial to show your interest and provide your domain and contact info.
  • Send a Tweet to @ChromiumDev with #smsreceiver and let us know where and how you're using it.

FAQ

Why did you not align with Safari's one-time-code?

We're exploring options similar to Safari's declarative autocomplete="one-time-code" approach as we go through our origin trial (early exploration) and we are interested to hear what developers and users think. Our imperative approach could provide a more flexible UX and reduce friction when verifying a phone number under certain circumstances. The declarative approach is easier to implement for developers, but requires a form field and at least several taps: focus on the input field, select the one-time-code, then submit the form. The approach we are exploring (inspired by what native Android apps have access to) means that people make only a single tap on browser UI inline on the page content.

Is it safe to use SMS as a way to authenticate?

While SMS OTP is useful to verify a phone number when the number is first provided, phone number verification via SMS must be used carefully for returning user re-authentication since phone numbers can be hijacked and recycled by carriers. SMS OTP is a convenient re-auth and recovery mechanism, but services should combine it with additional factors, such as a knowledge challenge, or use WebAuthn for strong authentication.

Can't we omit the browser's app hash?

We would like to remove it, but it's currently a platform restriction. We are working with the Android team to understand what's the best way to approach it.

Will an SMS message timeout?

Yes. We're planning to use AbortController to time the request out (tracking bug), but it's not implemented as of Chrome 78.

Will the apk hash change for an installed PWA?

No. A PWA's app hash is the same as the browser it runs in.

Can we localize the "For:" string required in the SMS?

Not right now. But ultimately, we are planning to remove it or otherwise allow for localization.

{% Aside %} Find more questions at the FAQ section in the explainer. {% endAside %}

You can’t perform that action at this time.