The SmsRetriever API provides access to Google services that help you retrieve SMS messages directed to your app without asking for android.permission.READ_SMS.

Many apps use phone numbers to verify the identity of a user. The app sends an SMS message containing an OTP (One Time Passcode) to the user, who then enters the OTP from the received SMS message to prove ownership of the phone number.

In Android, to provide a streamlined UX, an app may request the SMS read permission, and retrieve the OTP automatically. This is problematic since this permission allows the app to read other SMS messages which may contain the user's private information.

The SmsRetriever API solves this problem by providing app developers a way to automatically retrieve only the SMS directed to the app without asking for the SMS read permission or gaining the ability to read any other SMS messages on the device.

The recommended process for retrieving an SMS message using this API is as follows:

  1. [Android] Obtain the user’s phone number (for example, via CredentialsApi or manual input)
  2. [Android] Start SMS retriever (note: this will timeout after 5 minutes)
             // Get an instance of SmsRetrieverClient, used to start listening for a
             // matching SMS message.
             SmsRetrieverClient client = SmsRetriever.getClient(context);
             // Start SmsRetriever, which waits for ONE matching SMS message until timeout
             // (5 minutes). The matching SMS message will be sent via a Broadcast Intent
             // with action SmsRetriever#SMS_RETRIEVED_ACTION.
             Task<Void> task = client.startSmsRetriever();
             // Listen for success/failure of the start Task. If in a background thread,
             // this can be made blocking using Tasks.await(task, [timeout]);
             task.addOnSuccessListener(new OnSuccessListener<Void>() {
               public void onSuccess(Void aVoid) {
                 // Successfully started SmsRetriever
             task.addOnFailureListener(new OnFailureListener() {
               public void onFailure(@NonNull Exception e) {
                 // Failed to start SmsRetriever, inspect Exception for more details
  3. [Android] Send phone number to server and start verification process
  4. [Server] Generate one-time code and send formatted SMS to the phone number

    Send SMS containing an OTP using existing infrastructure. However, the message template must be changed to include one of the following prefixes:

    • [#]
    • \u200b\u200b
    The former is a visible prefix that will appear in the message contents, and the latter is an invisible unicode string, but requires unicode support for the message.

    The SMS must also contain an 11-character string at the end of the SMS which is a hash string derived from the app package name and certificate. This is static and should be a whitelisted precomputed value and not supplied by the client app.

    Given the app package name and the certificate, the hash string can be generated by the following steps:

    • Concatenate the app package name and the certificate with a space. In shell script:
                     input = "$package_name $certificate"
    • Encode the concatenated string with SHA-256. In shell script:
                     output = $(printf "$input" | shasum -a 256)
    • Truncate the beginning 9 bytes (18 hex chars). In shell script:
                     output = $(printf "$output" | cut -c1-18)
    • Encode by Base64 and truncate the beginning 11 chars. In shell script:
                     base64output = $(printf "$output" | xxd -r -p | base64 | cut -c1-11)

    The rest of the SMS message is flexible: it can contain any content/instructions and be localized, etc.

    Example SMS message contents:

             [#] Use 123456 as your code for Example App
    Where 123456 is the OTP and the hashed string is inserted inline at the end of the SMS message. The OTP is human readable and could be typed in manually by the user if need be.
  5. [Android] Receive SMS via Broadcast Intent
              * BroadcastReceiver to wait for SMS messages. This can be registered either
              * in the AndroidManifest or at runtime.  Should filter Intents on
              * SmsRetriever.SMS_RETRIEVED_ACTION.
             public class MyBroadcastReceiver extends BroadcastReceiver {
               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:
                       // Get SMS message contents
                       String message = (String) extras.get(SmsRetriever.EXTRA_SMS_MESSAGE);
                       // Extract one-time code from the message and complete verification
                     case CommonStatusCodes.TIMEOUT:
                       // Waiting for SMS timed out (5 minutes)
                       // Handle the error ...
  6. [Android] Extract the one-time code and pass it to the server

    Once the SMS hash been retrieved, use a regular expression or similar logic to extract the code and send it to the server.

  7. [Server] Verify code from SMS and set up user session or similar

    On the server, check that the code matches the one sent to the phone number being verified and complete the verification process by marking the number as verified and setting up user session, for example.


SmsRetrieverApi API interface for SmsRetriever. 


SmsRetriever The SmsRetriever API provides access to Google services that help you retrieve the SMS message directed to your app without asking for android.permission.READ_SMS. 
SmsRetrieverClient The main entry point for interacting with SmsRetriever.