July 7, 2020

Firebase OTP authentication in android

By Mohit Agrawal

Implement the Firebase phone number authentication in your android app

firebase_otp_5

Introduction

In most of the android app, we go through the sign-up process when we use it the first time. There are many ways to verify the authenticity of users like Google, Facebook, Instagram, and many more. But among all these phone or OTP authentications is very popular. It is because users have to just enter the mobile number. After that, the app will handle the remaining process ( most of the time app detects the OTP messages without user interaction ).

What is Firebase phone or OTP authentication?

It is one of the services provided by the Firebase. It is used to sign in users by sending a one time password to the user’s device.

Authentication of the users using OTP is very convenient but it is less secure than email or other ways of authentication.

Implementation of Firebase phone or OTP authentication in your android app

1 STEP: Create a new firebase project and connect it with your android app using the firebase assistant in the android studio. If you need more guidance in connecting your app to firebase then you can check out Firebase remote config in android.

I will recommend you to integrate the Firebase in your android project using the android assistant only but If you doing it manually then do not forget to add the SHA key to your firebase project.

2 STEP: Now open your firebase project console. Go to Authentication -> sign-in method. Here you need to enable the phone authentication option.

firebase_otp_1

3 STEP: Open app level build.gradle file and add the firebase auth dependency.

implementation 'com.google.firebase:firebase-auth:19.3.1'

4 STEP: In this step, We will design the 3 different activity and their XML files. Let’s see what are the activities which we are going to use.

MainActivity.kt is the landing page of the app. I have designed it as simple as possible. It has one spinner to choose the country code, one text field for the phone number, and one button for sending the OTP request.

firebase_otp_2
MainActivity.kt

As soon as we click on send OTP button then OTPValidation.kt (second activity) will open. Here the user will have to enter the OTP.

firebase_otp_4
OTPValidation.kt

If the entered OTP is correct then it will go to the SuccessActivity.kt (third activity)

Code for MainActivity.kt.

import android.content.Intent
import android.os.Bundle
import android.widget.ArrayAdapter
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        spinner.adapter = ArrayAdapter(
            this,
            android.R.layout.simple_spinner_dropdown_item,
            CountryData.countryNames
        )

        button.setOnClickListener {
            val code =
                CountryData.countryAreaCodes[spinner.selectedItemPosition]
            if (mobileNumber.text.count() == 10) {
                val i = Intent(this, OTPValidation::class.java).apply {
                    putExtra("mobileNumber", code+mobileNumber.text.toString())
                }
                startActivity(i)
            } else {
                Toast.makeText(this, "Enter 10 digits mobile number",Toast.LENGTH_LONG).show()
            }
        }
    }
}

I am using a simple check for 10 digits phone number. If the phone number is valid then I am passing it to the second activity.

Code for activity_main.xml.

<?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">

    <EditText
        android:id="@+id/mobileNumber"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="5dp"
        android:layout_marginLeft="5dp"
        android:layout_marginTop="200dp"
        android:layout_marginEnd="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginBottom="20dp"
        android:ems="10"
        android:hint="Mobile Number"
        android:inputType="phone"
        app:layout_constraintBottom_toTopOf="@+id/button"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/spinner"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="100dp"
        android:layout_marginLeft="100dp"
        android:layout_marginTop="20dp"
        android:layout_marginEnd="100dp"
        android:layout_marginRight="100dp"
        android:text="Send OTP"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/mobileNumber" />

    <Spinner
        android:id="@+id/spinner"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="10dp"
        android:layout_marginLeft="10dp"
        android:layout_marginEnd="5dp"
        android:layout_marginRight="5dp"
        app:layout_constraintBottom_toBottomOf="@+id/mobileNumber"
        app:layout_constraintEnd_toStartOf="@+id/mobileNumber"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/mobileNumber" />

</androidx.constraintlayout.widget.ConstraintLayout>

Code for OTPValidation.kt.

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import com.google.android.gms.tasks.OnCompleteListener
import com.google.firebase.FirebaseException
import com.google.firebase.FirebaseTooManyRequestsException
import com.google.firebase.auth.*
import kotlinx.android.synthetic.main.activity_o_t_p_validation.*

class OTPValidation : AppCompatActivity() {
    private var mVerificationId: String? = null
    private var mAuth: FirebaseAuth? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_o_t_p_validation)

        val mobileNumber = intent.getStringExtra("mobileNumber")

        mAuth = FirebaseAuth.getInstance()

        PhoneAuthProvider.getInstance().verifyPhoneNumber(
            "+91$mobileNumber", // Phone number to verify
            60, // Timeout duration
            java.util.concurrent.TimeUnit.SECONDS, // Unit of timeout
            this, // Activity (for callback binding)
            callbacks) // OnVerificationStateChangedCallbacks

        verifyButton.setOnClickListener {
            if (!otpTextField.text.isNullOrEmpty()) {
                verifyVerificationCode(otpTextField.text.toString())
            }
        }
    }

    private val callbacks: PhoneAuthProvider.OnVerificationStateChangedCallbacks =
        object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {

            override fun onVerificationCompleted(phoneAuthCredential: PhoneAuthCredential) {
                val code = phoneAuthCredential.smsCode
                if (code != null) {
                    verifyVerificationCode(code)
                }
            }

            override fun onVerificationFailed(e: FirebaseException) {
                // This callback is invoked in an invalid request for verification is made,
                // for instance if the the phone number format is not valid.
                if (e is FirebaseAuthInvalidCredentialsException) {
                    Toast.makeText(this@OTPValidation, e.message, Toast.LENGTH_LONG).show()
                } else if (e is FirebaseTooManyRequestsException) {
                    Toast.makeText(this@OTPValidation, e.message, Toast.LENGTH_LONG).show()
                }
            }

            override fun onCodeSent(
                s: String,
                forceResendingToken: PhoneAuthProvider.ForceResendingToken
            ) {
                super.onCodeSent(s, forceResendingToken)
                mVerificationId = s
                //mResendToken = forceResendingToken
            }
        }

    private fun verifyVerificationCode(code: String) {
        //creating the credential
        val credential = PhoneAuthProvider.getCredential(mVerificationId!!, code)

        //signing the user
        signInWithPhoneAuthCredential(credential)
    }

    private fun signInWithPhoneAuthCredential(credential: PhoneAuthCredential) {
        mAuth!!.signInWithCredential(credential)
            .addOnCompleteListener(
                this,
                OnCompleteListener<AuthResult?> { task ->
                    if (task.isSuccessful) {
                        //verification successful we will start the profile activity
                        Toast.makeText(this,"Success", Toast.LENGTH_LONG).show()
                        val i = Intent(this, SuccessActivity::class.java)
                        startActivity(i)
                    } else {
                        Toast.makeText(this,"Failed", Toast.LENGTH_LONG).show()
                    }
                })
    }
}

Code for activity_o_t_p_validation.xml

<?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=".OTPValidation">

    <EditText
        android:id="@+id/otpTextField"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="100dp"
        android:layout_marginLeft="100dp"
        android:layout_marginTop="200dp"
        android:layout_marginEnd="100dp"
        android:layout_marginRight="100dp"
        android:layout_marginBottom="30dp"
        android:ems="10"
        android:hint="Enter OTP"
        android:inputType="number"
        app:layout_constraintBottom_toTopOf="@+id/verifyButton"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/verifyButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="100dp"
        android:layout_marginLeft="100dp"
        android:layout_marginTop="30dp"
        android:layout_marginEnd="100dp"
        android:layout_marginRight="100dp"
        android:text="Verify"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/otpTextField" />
</androidx.constraintlayout.widget.ConstraintLayout>

Code for SuccessActivity.kt.

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle

class SuccessActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_success)
    }
}

Code for activity_success.xml.

<?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=".SuccessActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Welcome to the Warmodroid Tutorial"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

Firebase phone authentication does not work on simulator. So you need to have one physical device to run this project.

If you have followed everything till here then you will be able to get the OTP successfully. Let me know if you are getting any issue in the comment section.

Subscribe YouTube: More tutorials like this

I hope this blog post is useful for you, do let me know your opinion in the comment section below.
I will be happy to see your comments down below 👏.
Thanks for reading!!!

android android beginners tutorial android tutorial Animation API call API call in iOS async asynchronous cardview custom switch custom ui dark web dark web links deep web deep web links Dynamic gradient view facebook messenger firebase hosting firebase hosting tutorial firebase remote config firebase tutorials flutter flutter for beginner flutter tutorial flutter UI tutorial hacking hacking tutorial hashcat iOS ios tutorial ios ui tutorial kotlin listview in flutter Lottie animation Messenger for kids review onion links Roll the Dice app swift tech news tor tor browser tor links UISwitch wifi wifi hacking