Reading verification codes from SMS

2-Factor Authentication (2FA) systems use SMS to send the verification code very often. If the user is on his phone, the process could be simplified if the app reads the code from the SMS and logs the user in automatically.

Here's how to do it in an Android App.

Set required permissions

<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />

Create a BroadcastReceiver to get the Code from the SMS

public class SmsReceiver extends BroadcastReceiver {
    private static final String TAG = "###SMSReceiver";
    private OnSmsReceivedListener listener;

    public SmsReceiver(@NonNull OnSmsReceivedListener listener){
        this.listener = listener;
    }

    @Override
    public void onReceive(Context context, Intent intent) {

        final Bundle bundle = intent.getExtras();
        try {
            if (bundle != null) {
                Object[] pdusObj = (Object[]) bundle.get("pdus");
                if (pdusObj != null) {
                    for (Object aPdusObj : pdusObj) {
                        SmsMessage currentMessage = SmsMessage.createFromPdu((byte[]) aPdusObj);
                        String senderAddress = currentMessage.getDisplayOriginatingAddress();
                        String message = currentMessage.getDisplayMessageBody();

                        Log.v(TAG, "SMS: " + message + ", Sender: " + senderAddress);

                        // TODO: make sure the SMS is from the intended the sender

                        // get the verification code from the SMS
                        String verificationCode = getVerificationCode(message);
                        listener.onSmsReceived(verificationCode);
                        if (verificationCode != null) {
                            Log.v(TAG, "Verification Code: " + verificationCode);
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String getVerificationCode(String message) {
        Pattern pattern = Pattern.compile("([\\d]{6})");
        Matcher m = pattern.matcher(message);
        if(m.find()){
            return m.group(1);
        }
        return null;
    }

    public interface OnSmsReceivedListener {
        void onSmsReceived(String code);
    }
}

Initialize receiver

Next, we create an instance of the SmsReceiver in the appropriate Activity class.

private SmsReceiver smsReceiver = new SmsReceiver(new SmsReceiver.OnSmsReceivedListener() {
    @Override
    public void onSmsReceived(String code) {
        if(code == null) {
            // Code not found
            // TODO: handle this
            // You might only need to print some log message here
        }
        else {
            // TODO: handle event
        }
    }
});

And register it

@Override
protected void onStart() {
    super.onStart();
    registerReceiver(smsReceiver, new IntentFilter("android.provider.Telephony.SMS_RECEIVED"));
}

@Override
protected void onStop() {
    super.onStop();
    unregisterReceiver(smsReceiver);
}

Ideally, you might want to register the receiver in onCreate() and unregister it when the user navigates out of the activity.

Screenshot

A working sample with complete source code is on Github.
You may download the code archive from here.