Firebase Phone Authentication In Android

Android

Introduction

As discussed in our previous posts, Firebase provides User Authentication in many types as Email, Google Plus, Facebook, Phone Authentication and more. We already have seen or heard about OTP authentication for mobile app users. In this article, we will learn a very useful feature of Firebase Phone Authentication.

To learn about Firebase Email authentication, read my posts here.

  1. Firebase User Authentication In Android - Part One
  2. Firebase User Authentication In Android - Part Two

Firebase Phone Authentication

Google's Firebase provides free service for a limited amount of authentication per month. However, if you need to sign in a very high volume of users with phone authentication, you might need to upgrade your pricing plan. You can view the pricing page here.

You can use Firebase Authentication to sign in a user by sending an SMS message to the user's phone. The user signs in using a one-time code contained in the SMS message.

 Firebase Setup

Before starting to code, we have to setup firebase for Android and enable Phone Authentication. If you are new to firebase, the following link will be useful to know the method for setting up the project in firebase.

https://androidmads.blogspot.in/2016/10/android-getting-started-with-firebase.html

After setting up, open Authentication sign-in method and enable phone authentication method as shown in the following figure.

Android

 

You should add SHA Fingerprint in your application. The following terminal will be used to get the SHA Fingerprint with Command Prompt in Windows for debug mode.

  1. keytool -list -v -keystore "%USERPROFILE%\.android\debug.keystore" -alias androiddebugkey -storepass android -keypass android  

Coding Part

I have split this part into 3 steps as follows.

  • Step 1: Creating a New Project with Empty Activity.
  • Step 2: Setting up the Firebase Library.
  • Step 3: Implementation of Firebase Phone Authentication.

Step 1 - Creating a New Project with Android Studio

  1. Open Android Studio and Select Create a new project.
  2. Name the project as your wish and select your activity template.

    Android

  3. Click finish button to create a new project in Android Studio.

Step 2- Setting up the Firebase Library

In this part, we will see how to set up the library for the project.

  1. Open your project level build.gradle file and add the following lines in dependencies
    1.  {  
    2.     …  
    3.     classpath 'com.google.gms:google-services:3.1.0'  
    4.               …  
    5. }  
  1. Then add the following lines in all projects in the project level build.gradle file.
    1. allprojects {  
    2.     repositories {  
    3.         google()  
    4.         jcenter()  
    5.         maven {  
    6.             url "https://maven.google.com"  
    7.         }  
    8.     }  
    9. }  
  1. Then add the following lines in app level build.gradle file to apply google services to your project.
    1. dependencies {  
    2.     ...  
    3.     implementation 'com.google.firebase:firebase-auth:11.8.0'  
    4. }  
    5. apply plugin: 'com.google.gms.google-services'  
  1. Then click “Sync Now” to setup your project.

Step 3 - Implementation of Firebase Phone Authentication

In this step, we will learn about, How to

  • send verification code
  • validates verification success & failure
  • manage sign-in & sign-out from the application
Send Verification Code
  • To verify the user’s phone number, we have to prompt users to enter the phone number.
  • Then send the phone number to firebase and request to validate the user’s phone number.
  • It is achieved by PhoneAuthProvider as shown in the following code snippet.
    1. PhoneAuthProvider.getInstance().verifyPhoneNumber(  
    2.                 phoneNumber,        // Phone number to verify  
    3.                 60,                 // Timeout duration  
    4.                 TimeUnit.SECONDS,   // Unit of timeout  
    5.                 this,               // Activity (for callback binding)  
    6.                 mCallbacks);        // OnVerificationStateChangedCallbacks  
Validates Authentication Success & Failure
  • mCallbacks is used to know the verification status and the callback method is implemented as in the following.
    1. mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {  
    2.     @Override  
    3.     public void onVerificationCompleted(PhoneAuthCredential credential) {  
    4.         Log.d(TAG, "onVerificationCompleted:" + credential);  
    5.         signInWithPhoneAuthCredential(credential);  
    6.     }  
    7.   
    8.     @Override  
    9.     public void onVerificationFailed(FirebaseException e) {  
    10.         Log.w(TAG, "onVerificationFailed", e);  
    11.         if (e instanceof FirebaseAuthInvalidCredentialsException) {  
    12.             mPhoneNumberField.setError("Invalid phone number.");  
    13.         } else if (e instanceof FirebaseTooManyRequestsException) {  
    14.             Snackbar.make(findViewById(android.R.id.content), "Quota exceeded.",  
    15.                     Snackbar.LENGTH_SHORT).show();  
    16.         }  
    17.     }  
    18.   
    19.     @Override  
    20.     public void onCodeSent(String verificationId,  
    21.                            PhoneAuthProvider.ForceResendingToken token) {  
    22.         Log.d(TAG, "onCodeSent:" + verificationId);  
    23.         mVerificationId = verificationId;  
    24.         mResendToken = token;  
    25.     }  
    26. };  
  • Here,

    • onVerificationCompleted(PhoneAuthCredential)
      This method is called when the user number verified successfully.

    • onVerificationFailed(FirebaseException)
      This method is called when an error occurred during verification.

    • onCodeSent(String verificationId, PhoneAuthProvider.ForceResendingToken)
      This method is called when the verification code is send to the user via SMS.
  • Phone Authentication Credentials can be read from PhoneAuthProvider as shown in the following snippets.
    1. PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, code);  
    2. // verificationId can be found in onCodeSent function in callback functionality  
    3. // code is retrieved from SMS send by Firebase  
Manage Sign-In & Sign-Out
  • The retrieved credentials are used to sign in to application. It can achieved by the following snippet.
    1. mAuth.signInWithCredential(credential)  
    2.             .addOnCompleteListener(thisnew OnCompleteListener() {  
    3.                 @Override  
    4.                 public void onComplete(@NonNull Task task) {  
    5.                     if (task.isSuccessful()) {  
    6.                         Log.d(TAG, "signInWithCredential:success");  
    7.                         FirebaseUser user = task.getResult().getUser();  
    8.                         startActivity(new Intent(PhoneAuthActivity.this, MainActivity.class));  
    9.                         finish();  
    10.                     } else {  
    11.                         Log.w(TAG, "signInWithCredential:failure", task.getException());  
    12.                         if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) {  
    13.                             mVerificationField.setError("Invalid code.");  
    14.                         }  
    15.                     }  
    16.                 }  
    17.             });  
  • Sign-Out from the app will be done from the following snippet.
    1. FirebaseAuth mAuth = FirebaseAuth.getInstance();  
    2. mAuth.signOut();  

Full Code

You can find the full code implementation here.

  1. public class PhoneAuthActivity extends AppCompatActivity implements  
  2.         View.OnClickListener {  
  3.   
  4.     EditText mPhoneNumberField, mVerificationField;  
  5.     Button mStartButton, mVerifyButton, mResendButton;  
  6.   
  7.     private FirebaseAuth mAuth;  
  8.     private PhoneAuthProvider.ForceResendingToken mResendToken;  
  9.     private PhoneAuthProvider.OnVerificationStateChangedCallbacks mCallbacks;  
  10.     String mVerificationId;  
  11.   
  12.     private static final String TAG = "PhoneAuthActivity";  
  13.   
  14.     @Override  
  15.     protected void onCreate(@Nullable Bundle savedInstanceState) {  
  16.         super.onCreate(savedInstanceState);  
  17.         setContentView(R.layout.activity_phone);  
  18.   
  19.         mPhoneNumberField = (EditText) findViewById(R.id.field_phone_number);  
  20.         mVerificationField = (EditText) findViewById(R.id.field_verification_code);  
  21.   
  22.         mStartButton = (Button) findViewById(R.id.button_start_verification);  
  23.         mVerifyButton = (Button) findViewById(R.id.button_verify_phone);  
  24.         mResendButton = (Button) findViewById(R.id.button_resend);  
  25.   
  26.         mStartButton.setOnClickListener(this);  
  27.         mVerifyButton.setOnClickListener(this);  
  28.         mResendButton.setOnClickListener(this);  
  29.   
  30.         mAuth = FirebaseAuth.getInstance();  
  31.         mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {  
  32.             @Override  
  33.             public void onVerificationCompleted(PhoneAuthCredential credential) {  
  34.                 Log.d(TAG, "onVerificationCompleted:" + credential);  
  35.                 signInWithPhoneAuthCredential(credential);  
  36.             }  
  37.   
  38.             @Override  
  39.             public void onVerificationFailed(FirebaseException e) {  
  40.                 Log.w(TAG, "onVerificationFailed", e);  
  41.                 if (e instanceof FirebaseAuthInvalidCredentialsException) {  
  42.                     mPhoneNumberField.setError("Invalid phone number.");  
  43.                 } else if (e instanceof FirebaseTooManyRequestsException) {  
  44.                     Snackbar.make(findViewById(android.R.id.content), "Quota exceeded.",  
  45.                             Snackbar.LENGTH_SHORT).show();  
  46.                 }  
  47.             }  
  48.   
  49.             @Override  
  50.             public void onCodeSent(String verificationId,  
  51.                                    PhoneAuthProvider.ForceResendingToken token) {  
  52.                 Log.d(TAG, "onCodeSent:" + verificationId);  
  53.                 mVerificationId = verificationId;  
  54.                 mResendToken = token;  
  55.             }  
  56.         };  
  57.     }  
  58.   
  59.     private void signInWithPhoneAuthCredential(PhoneAuthCredential credential) {  
  60.         mAuth.signInWithCredential(credential)  
  61.                 .addOnCompleteListener(thisnew OnCompleteListener<AuthResult>() {  
  62.                     @Override  
  63.                     public void onComplete(@NonNull Task<AuthResult> task) {  
  64.                         if (task.isSuccessful()) {  
  65.                             Log.d(TAG, "signInWithCredential:success");  
  66.                             FirebaseUser user = task.getResult().getUser();  
  67.                             startActivity(new Intent(PhoneAuthActivity.this, MainActivity.class));  
  68.                             finish();  
  69.                         } else {  
  70.                             Log.w(TAG, "signInWithCredential:failure", task.getException());  
  71.                             if (task.getException() instanceof FirebaseAuthInvalidCredentialsException) {  
  72.                                 mVerificationField.setError("Invalid code.");  
  73.                             }  
  74.                         }  
  75.                     }  
  76.                 });  
  77.     }  
  78.   
  79.   
  80.     private void startPhoneNumberVerification(String phoneNumber) {  
  81.         PhoneAuthProvider.getInstance().verifyPhoneNumber(  
  82.                 phoneNumber,        // Phone number to verify  
  83.                 60,                 // Timeout duration  
  84.                 TimeUnit.SECONDS,   // Unit of timeout  
  85.                 this,               // Activity (for callback binding)  
  86.                 mCallbacks);        // OnVerificationStateChangedCallbacks  
  87.     }  
  88.   
  89.     private void verifyPhoneNumberWithCode(String verificationId, String code) {  
  90.         PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, code);  
  91.         signInWithPhoneAuthCredential(credential);  
  92.     }  
  93.   
  94.     private void resendVerificationCode(String phoneNumber,  
  95.                                         PhoneAuthProvider.ForceResendingToken token) {  
  96.         PhoneAuthProvider.getInstance().verifyPhoneNumber(  
  97.                 phoneNumber,        // Phone number to verify  
  98.                 60,                 // Timeout duration  
  99.                 TimeUnit.SECONDS,   // Unit of timeout  
  100.                 this,               // Activity (for callback binding)  
  101.                 mCallbacks,         // OnVerificationStateChangedCallbacks  
  102.                 token);             // ForceResendingToken from callbacks  
  103.     }  
  104.   
  105.     private boolean validatePhoneNumber() {  
  106.         String phoneNumber = mPhoneNumberField.getText().toString();  
  107.         if (TextUtils.isEmpty(phoneNumber)) {  
  108.             mPhoneNumberField.setError("Invalid phone number.");  
  109.             return false;  
  110.         }  
  111.         return true;  
  112.     }  
  113.     @Override  
  114.     public void onStart() {  
  115.         super.onStart();  
  116.         FirebaseUser currentUser = mAuth.getCurrentUser();  
  117.         if (currentUser != null) {  
  118.             startActivity(new Intent(PhoneAuthActivity.this, MainActivity.class));  
  119.             finish();  
  120.         }  
  121.     }  
  122.   
  123.     @Override  
  124.     public void onClick(View view) {  
  125.         switch (view.getId()) {  
  126.             case R.id.button_start_verification:  
  127.                 if (!validatePhoneNumber()) {  
  128.                     return;  
  129.                 }  
  130.                 startPhoneNumberVerification(mPhoneNumberField.getText().toString());  
  131.                 break;  
  132.             case R.id.button_verify_phone:  
  133.                 String code = mVerificationField.getText().toString();  
  134.                 if (TextUtils.isEmpty(code)) {  
  135.                     mVerificationField.setError("Cannot be empty.");  
  136.                     return;  
  137.                 }  
  138.   
  139.                 verifyPhoneNumberWithCode(mVerificationId, code);  
  140.                 break;  
  141.             case R.id.button_resend:  
  142.                 resendVerificationCode(mPhoneNumberField.getText().toString(), mResendToken);  
  143.                 break;  
  144.         }  
  145.   
  146.     }  
  147.   
  148. }  

Download Code

You can download the full source code of the article in GitHub. If you like this article, do star the repo in GitHub. Hit like the article.