In this blog, I will show how to auto read OTP in android with the help of SMS User Consent API. In our previous blog, we have learned Automatic SMS Verification Android using SMS Retriever API. But it has some difficulty for example
- SMS should start with <#> tag,
- SMS should end with application hash code, etc.
In this article, I’m going to show you the implementation auto-read OTP using SMS User Consent API. It is complements of SMS Retriever API. Using SMS User Consent API we can achieve auto read OTP by allowing an app to prompt the user to grant access to the content of a single SMS message. When the user gives consent, the app can access the entire message to automatically complete SMS verification.
Flow for Auto Read OTP with SMS User Consent API



Image source google developers website.
There are 3 steps of user flow of this SMS User Consent API
- Start – The first thing you have to start is listening before sending the message or OTP to the server.
- Prompt – When the user’s device receives the SMS message containing a one-time code, Google Play services display the contents of the message to the user and asks for consent to make that text available to your app.
- Read Message – If the user consents, the entire SMS message is made available to your app.
Message Criteria
Google play services imposed the followings SMS criteria
- It contains a one-time password– The should message contains a 4–10 character alphanumeric string with at least one number.
- Contacts – The message was sent by a phone number that’s not in the user’s contacts.
- Timing – The API will look for the One Time Code for a maximum time of 5 minutes.
1. Let’s create a new project in Android Studio
Open to an android studio and create a new project. That project we will implement auto read OTP features. So I’m adding few strings in strings.xml file that we will use this project.
<resources> <string name="app_name">SMS verification</string> <string name="send_otp">Send OTP</string> <string name="generate_otp">Generate OTP</string> <string name="received_message">Received Message</string> <string name="verify_otp">Verify OTP</string> </resources>
2. Add SMS User Consent API libraries in your app.
We should add below dependencies in app-level build.gradle in your project.
// add these lines in your app build.gradle implementation 'com.google.android.gms:play-services-auth:17.0.0' implementation 'com.google.android.gms:play-services-auth-api-phone:17.1.0'
3. Listen to the incoming messages
The next step is to listen to incoming messaging. we can start listening for incoming messages using below method. We can add sender phone number, SMS User Consent API will only trigger on messages from this number. I’m adding null here
private void startSmsUserConsent() { SmsRetrieverClient client = SmsRetriever.getClient(this); //We can add sender phone number or leave it blank // I'm adding null here client.startSmsUserConsent(null).addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void aVoid) { Toast.makeText(getApplicationContext(), "On Success", Toast.LENGTH_LONG).show(); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Toast.makeText(getApplicationContext(), "On OnFailure", Toast.LENGTH_LONG).show(); } }); }
4. Create a BroadcastReceiver named is SmsBroadcastReceiver
In SmsBroadcastReceiverListener we will catch SMS and set back using SmsBroadcastReceiverListener callback methods.
package com.smsverification; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Bundle; import com.google.android.gms.auth.api.phone.SmsRetriever; import com.google.android.gms.common.api.CommonStatusCodes; import com.google.android.gms.common.api.Status; public class SmsBroadcastReceiver extends BroadcastReceiver{ SmsBroadcastReceiverListener smsBroadcastReceiverListener; @Override public void onReceive(Context context, Intent intent) { if (intent.getAction() == SmsRetriever.SMS_RETRIEVED_ACTION) { Bundle extras = intent.getExtras(); Status smsRetrieverStatus = (Status) extras.get(SmsRetriever.EXTRA_STATUS); switch (smsRetrieverStatus.getStatusCode()) { case CommonStatusCodes.SUCCESS: Intent messageIntent = extras.getParcelable(SmsRetriever.EXTRA_CONSENT_INTENT); smsBroadcastReceiverListener.onSuccess(messageIntent); break; case CommonStatusCodes.TIMEOUT: smsBroadcastReceiverListener.onFailure(); break; } } } public interface SmsBroadcastReceiverListener { void onSuccess(Intent intent); void onFailure(); } }
5. Show the permission consent
When the broadcast receiver catch any message that contains OTP, Google paly services display is contents( BottomSheet ) for asking permission. If the user allows then full messing is available to your app. So let’s register broadcast receiver.
private void registerBroadcastReceiver() { smsBroadcastReceiver = new SmsBroadcastReceiver(); smsBroadcastReceiver.smsBroadcastReceiverListener = new SmsBroadcastReceiver.SmsBroadcastReceiverListener() { @Override public void onSuccess(Intent intent) { startActivityForResult(intent, REQ_USER_CONSENT); } @Override public void onFailure() { } }; IntentFilter intentFilter = new IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION); registerReceiver(smsBroadcastReceiver, intentFilter); } @Override protected void onStart() { super.onStart(); registerBroadcastReceiver(); } @Override protected void onStop() { super.onStop(); unregisterReceiver(smsBroadcastReceiver); }
6. Receive message in onActivityResult()
If the user consents, the entire SMS message is made available to your app. we will catch messaging in
@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQ_USER_CONSENT) { if ((resultCode == RESULT_OK) && (data != null)) { //That gives all message to us. // We need to get the code from inside with regex String message = data.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE); Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show(); textViewMessage.setText( String.format("%s - %s", getString(R.string.received_message), message)); getOtpFromMessage(message); } } }
7. Extract OTP from messaging.
Suppose our messaging is “Your OTP is 123456. Please do not share OTP with others “. Now you have to extract OTP from methods using below method.
private void getOtpFromMessage(String message) { // This will match any 6 digit number in the message Pattern pattern = Pattern.compile("(|^)\\d{6}"); Matcher matcher = pattern.matcher(message); if (matcher.find()) { otpText.setText(matcher.group(0)); } }
8. I’m modifying main activity layout for demonstration
For creating a fully functional sample app, I’m adding TextView for showing messaging and edit text for showing OTP.
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" > <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/verify_otp" android:textAllCaps="false" android:textSize="18sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/textViewMessage" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_marginTop="24dp" android:layout_marginEnd="16dp" android:gravity="center" android:textSize="16sp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/button" tools:text="@string/received_message" /> <ImageView android:id="@+id/imageView" android:layout_width="150dp" android:layout_height="150dp" android:layout_marginTop="32dp" app:layout_constraintBottom_toTopOf="@+id/editTextOTP" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:srcCompat="@drawable/ic_otp" /> <EditText android:id="@+id/editTextOTP" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_marginEnd="16dp" android:layout_marginBottom="16dp" android:ems="10" android:gravity="center" android:hint="OTP" android:inputType="number" app:layout_constraintBottom_toTopOf="@+id/button" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
9. We almost done, put all java code together in activity files.
package com.smsverification; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import com.google.android.gms.auth.api.phone.SmsRetriever; import com.google.android.gms.auth.api.phone.SmsRetrieverClient; import com.google.android.gms.tasks.OnFailureListener; import com.google.android.gms.tasks.OnSuccessListener; import java.util.regex.Matcher; import java.util.regex.Pattern; public class MainActivity extends AppCompatActivity { private static final int REQ_USER_CONSENT = 200; SmsBroadcastReceiver smsBroadcastReceiver; Button verifyOTP; TextView textViewMessage; EditText otpText; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // find view by ids verifyOTP = findViewById(R.id.button); textViewMessage = findViewById(R.id.textViewMessage); otpText = findViewById(R.id.editTextOTP); startSmsUserConsent(); } private void startSmsUserConsent() { SmsRetrieverClient client = SmsRetriever.getClient(this); //We can add sender phone number or leave it blank // I'm adding null here client.startSmsUserConsent(null).addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void aVoid) { Toast.makeText(getApplicationContext(), "On Success", Toast.LENGTH_LONG).show(); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Toast.makeText(getApplicationContext(), "On OnFailure", Toast.LENGTH_LONG).show(); } }); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQ_USER_CONSENT) { if ((resultCode == RESULT_OK) && (data != null)) { //That gives all message to us. // We need to get the code from inside with regex String message = data.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE); Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show(); textViewMessage.setText( String.format("%s - %s", getString(R.string.received_message), message)); getOtpFromMessage(message); } } } private void getOtpFromMessage(String message) { // This will match any 6 digit number in the message Pattern pattern = Pattern.compile("(|^)\\d{6}"); Matcher matcher = pattern.matcher(message); if (matcher.find()) { otpText.setText(matcher.group(0)); } } private void registerBroadcastReceiver() { smsBroadcastReceiver = new SmsBroadcastReceiver(); smsBroadcastReceiver.smsBroadcastReceiverListener = new SmsBroadcastReceiver.SmsBroadcastReceiverListener() { @Override public void onSuccess(Intent intent) { startActivityForResult(intent, REQ_USER_CONSENT); } @Override public void onFailure() { } }; IntentFilter intentFilter = new IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION); registerReceiver(smsBroadcastReceiver, intentFilter); } @Override protected void onStart() { super.onStart(); registerBroadcastReceiver(); } @Override protected void onStop() { super.onStop(); unregisterReceiver(smsBroadcastReceiver); } }
Congrats, Let’s use the SMS content API is your application
Conclusion
In this post, we learned how to auto-read OTP android using SMS content API in our application. So let’s recap the step of implementation, basically, three major steps Start Listening messaging, show prompt and Read messaging.
I hope it’s helpful for you, Help me by sharing this post with all your friends who learning android app development.
Get Solution Code
Keep Learning 🙂
18 Comments
Receiving the otp but it is taking length-1 of the actual otp. Means if sms contains 6 digit otp then it is not taking and if it is more than 6 like 7 or more then it is fetching 6 digits out of it. Please help and thanks for the code.
can you please connect over facebook with connect and help you out
Hi Morris,
Thank you so much…
This is really helpful…and it worked fine…
I also implemented this …But I got warning from playstore..Issue is Intent Redirection Issue
We need to register the broadcase receiver in androidManifest also. You can see that in the zip file
I am not able to download code , Please help with code base
what error you are facing
Is there any way to avoid for asking permission to the user to read the message each time OTP comes?
Nope
some device not showing permission popup what to do for that please help
Hi I have query regarding SMS Retriever API and SMS user consent Api.
Can you tell me which one will be better? and Is there any disadvantage of SMS user consent Api??
I’m not sure which one is better, If you ask me I will prefer SMS Retriever API
Is SMS User consent Api is supportable for all android versions?
Bro, if sender number has in your contact it will not work. Delete user from your contact and retry then it will work 🙂
We have got always for timeout status. when using the startSmsUserConsent(“+91781281XXX”). Please help me what is an error.
Hello,
I still didnt understand.
how SMS will get read, if the recieved SMS is not in the given format.(ex: ….)
where you are modifying the code for this?
you mean, client.startSmsUserConsent(null).addOnSuccessListener(new OnSuccessListener()
this will not look for the format?
Here I’m doing
Pattern pattern = Pattern.compile("(|^)\\d{6}");
Hello,
I have try with shared code, but OTP didn’t read automatically. I have used unknown number to send the message, “OTP code is 232441 for testing” but didn’t worked. I have tested it on HTC Desire 628 Android 5.1. Please help me with that.