To build apps that make use of phone numbers, it's often crucial to verify that
the user owns a number. Doing this can be tricky from a UX perspective, not
least in understanding phone number formats in different locales, but also in
providing a verification mechanism that isn't cumbersome or using intrusive
device permissions, such as the ability to read all of a user's SMS.
There are many libraries for efficient pre-built phone authentication, such as
Firebase Phone Auth, but if
you are an advanced developer and need to build this functionality yourself,
Google Play Services has two new APIs that help you obtain a user's phone number
and verify it via SMS without device permissions: the Phone
Selector and SMS Retriever. Apps like href="https://play.google.com/store/apps/details?id=com.flipkart.android">Flipkart
have seen a 12% increase of success rates in phone number sign-up flows using
these methods.
The
href="https://developers.google.com/identity/sms-retriever/overview">steps
for using these with your server can be seen here:
In this post we'll show the code that you need to provide a phone number
selector to your users, and then use this with the SMS retriever API to request
a verification code from your server that the Android device will automatically
receive and parse with no input from the user.
Note: Before you begin you'll need to build and test this is a
device with a phone number that can receive SMS and runs Google Play services
10.2.x and higher.
Using the Phone Selector to get the number
The first step is to have the user initiate SMS verification from within your
app. Your app might prompt the user to enter a phone number, and you can use the
Phone Selector to make this easier, using code like this:
class="prettyprint">// Construct a request for phone numbers and show the picker
private void requestHint() {
HintRequest hintRequest = new HintRequest.Builder()
.setPhoneNumberIdentifierSupported(true)
.build();
PendingIntent intent = Auth.CredentialsApi.getHintPickerIntent(
apiClient, hintRequest);
startIntentSenderForResult(intent.getIntentSender(),
RESOLVE_HINT, null, 0, 0, 0);
}
The HintRequest builder tells Play Services that a phone number identifier is
needed. This is then used to create and start an intent, which will show a Play
Service dialog to the user allowing them to select their phone number to share
with the app. This API does not require any permissions, and displays the
number(s) available on the phone or Google Account for the user to select.
When the user selects a phone number it will be returned to the application in
onActivityResult in E164
format on devices running the latest version of Play Services. Note that in
some cases, depending on your phone, you may not get a phone number, so be sure
to check if the credential is non-null. If you don't have a number, you'll need
to provide a way for your user to type it in manually.
class="prettyprint">// Obtain the phone number from the result
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RESOLVE_HINT) {
if (resultCode == RESULT_OK) {
Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY);
// credential.getId(); <-- E.164 format phone number on 10.2.+ devices
}
}
}
At this point you'll have a phone number string for your user. While this is
useful, you'll likely want to verify that the user owns this particular number,
for example to allow them to send or retrieve message with other users or
identifying themselves with this number.
Using the SMS Verification API to verify the number
A simple way to verify phone number ownership is by sending an SMS to the
number, containing a one time verification code, and having them enter that into
your app. The SMS Verification API gives you the ability for the app to listen
for an incoming SMS from which it can parse the code automatically.
To get started, your app will SmsRetrieverClient
with code like this:
Task<Void> task = client.startSmsRetriever();
task.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
// successfully started an SMS Retriever for one SMS message
}
});
task.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
});
);
It's pretty simple -- you get an SMS Retriever client and then start a task for
it. The task has an on Success listener as well as an on Failure one to
override. After starting the SMS Retriever, you'd send the user's phone number
to your server and start it's workflow for generating the message and sending it
to that number.
The message needs to be constructed in a specific way. The message must fit in
an SMS message, so it can't be longer than 140 bytes. It needs to start with a
specific prefix: '<#>' or two consecutive zero-width space characters (U+200B).
See the href="https://developers.google.com/identity/sms-retriever/verify">documentation
for your more information. It must end with an 11-character hash that identifies
your app, described below.
Example:
<#> Use 123456 as your verification code in Example App!
FA+9qCX9VSu
The one-time verification code can be any string: you can simply generate a
random number. The message needs to end with a hash that is determined according
to the procedures href="https://developers.google.com/identity/sms-retriever/verify#computing_your_apps_hash_string">here.
Google Play services will use this hash to determine which app the verification
message is for. You only need to generate this hash once for your app package
and signing certificate: it won't change and shouldn't be supplied by the client
app.
Your server can then send the message to the phone using your existing SMS
infrastructure or service. When this message is received, Google Play services
broadcasts an intent which contains the text of the message. Here's the code:
class="prettyprint">public class MySMSBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (SmsRetriever.SMS_RETRIEVED_ACTION.equals(intent.getAction())) {
Bundle extras = intent.getExtras();
Status status = (Status) extras.get(SmsRetriever.EXTRA_STATUS);
switch(status.getStatusCode()) {
case CommonStatusCodes.SUCCESS:
String message = (String) extras.get(SmsRetriever.EXTRA_SMS_MESSAGE);
break;
case CommonStatusCodes.TIMEOUT:
break;
}
}
}
}
In the onReceive of the broadcast receiver you get the extras, and pull the
status from there. If the status indicates that the message was successfully
received, you can pull the message from the extras. From here you can parse out
the verification code and send it back to your server to confirm phone number
ownership.
For more information, check out the full href="https://developers.google.com/identity/sms-retriever/">documentation
and this year's Google I/O
talk.
Testimonies of Early Adopters
Our early partners who use this API love it. Here are some testimonials from
them:
href="https://www.twilio.com/blog/2017/05/twilio-verification-sdk-android-app-sms-permissions-phone-verification-has-never-been-easier.html">Twilio
observed and blogged that Android SMS Verification has never been easier.
"If you're a developer building mobile apps on Android that use phone
numbers to register and identify user accounts, you should be using Twilio
Verification SDK for Android for the quickest way to solve the problem of
providing a smooth, secure and easy sign-up flow." - Simon Thorpe, Product
Owner at Twilio
href="https://authy.com/blog/authy-for-android-app-is-now-easier-to-use-and-safer-too/">Authy
loved the fact that these APIs work with their existing SMS infrastructure
without requiring many changes.
"Adding Phone Selector + SMS Retriever into Authy 2FA app delivers magical
UX for users while retaining the high security our application requires." --
Serge Kruppa, Head of Authy Engineering
href="https://www.telesign.com/blog/post/telesign-app-verify-now-offers-autosms-mode-with-even-lower-friction-during-android-user-verification/">Telesign
observed better UX, increased security and higher conversion rates with the same
backend framework.
"One significant advantage of this verification mode with lower friction is
that customers might be able to see increased conversion rates for user sign-up
and registration scenarios.
Enhanced security is also a benefit as Google Play Services only provides
access to the SMS message to the targeted application based on the application
hash inside the message." -- Priyesh Jain (Post author)
0 comments