How to Implement OTP-Mobile Verification using Firebase Authentication

Abdullah Aimen
6 min readDec 3, 2019

Introduction

Most of the modern apps nowadays use SMS mobile login via sending verification code to the preregistered mobile number. In this tutorial, we are going to implement firebase authentication via SMS code to user’s mobile.

Prerequisites

  • you suppose to have the latest version of Android Studio.
  • Android smartphone for testing, as OTP cannot be sent to an emulator.
  • firebase Account to create a new project and enable mobile login via OTP.

App Overview

Create a new project for implementing the OTP-Authentication feature provided by Firebase. The app will have a simple activity with multiple buttons and EditTexts for typing mobile number, OTP and Request OTP, verify OTP and Logout the session. Simply the user will enter his mobile number then press request OTP. a timer will countdown waiting for OTP-token to be sent as SMS to that number. once the user got the OTP, he can type and Press verify. If the OTP does not match then it will pop a toast message, “Incorrect OTP”. Users can logout after successful verification.

Here is what the app finish will look like:

Note: Due to security issues the phone number was hidden.

Setting Up Project

Step #1: Create A New Android Studio Project

  • Start Android Studio and Click on “new project”.
  • Give your application a name, mine is “firebaseCodeLab”.
  • Click next and choose the Target android device.
  • next, choose an empty activity to keep things simple.
  • next, name your Activity and click finish to build the project.

Step #2: Add Firebase To your project

  • Go to Firebase Console
  • Sign in with your Gmail
  • On the welcome screen of Firebase click on Add project
  • Then register your app as below
  • you can get the SHA-1 from:
open gradle from the left side menu, then press signingReport.
  • the SHA-1 will appear as below
SHA-1 for debugging Version
  • then press register app and follow the steps.
google-services.json file to be included inside our app module

After that, add the dependencies to your project as described below

Adding google service to project/build.gradle
Adding dependencies to the project module

Don’t forget to give internet permission before testing :’)

Adding internet permission in the manifest file

Now go back to Firebase console and click on Project Overview. In Discover Firebase section there is a card named Authentication, click on GET STARTED on Authentication card.

select Sign-in method

Press on the Phone section and the following image will appear.

enable the toggle button

by enabling the toggle button, you have successfully added the OTP-Authentication feature to your project and its ready for usage.

NOTE: you can add phone numbers with fixed OTP-token for testing purposes. it's optional and recommended to set it up to avoid blocking your device by google while testing.

Screen Design

the style will look like

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.MaterialComponents.Light">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>

and colors…

<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#008577</color>
<color name="colorPrimaryDark">#00574B</color>
<color name="colorAccent">#D81B60</color>
</resources>

main_activity.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">

<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00:60"
app:layout_constraintBaseline_toBaselineOf="@+id/button"
app:layout_constraintEnd_toStartOf="@+id/button"
app:layout_constraintHorizontal_bias="0.95"
app:layout_constraintStart_toStartOf="parent" />

<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:text="Current User:"
app:layout_constraintBottom_toTopOf="@+id/textInputLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintEnd_toStartOf="@+id/textView4"
app:layout_constraintHorizontal_bias="0.19"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.37" />

<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="----"
app:layout_constraintBaseline_toBaselineOf="@+id/textView3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/textView3"
app:layout_constraintStart_toStartOf="parent" />

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/textInputLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:hint="mobile no"
app:errorEnabled="true"
app:helperText="type your number"
app:helperTextEnabled="true"
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"
app:layout_constraintVertical_bias="0.2">

<com.google.android.material.textview.MaterialAutoCompleteTextView
android:id="@+id/outlined_exposed_dropdown_editable"
android:layout_width="match_parent"
android:inputType="phone"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>


<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Verify OTP"
android:textAllCaps="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/logout"
app:layout_constraintHorizontal_bias="0.50"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textInputET"
app:layout_constraintVertical_bias="0.0" />

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/textInputET"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint=" Enter OTP"
app:helperText=" Enter OTP"
app:helperTextEnabled="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/button"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button"
app:layout_constraintVertical_bias="0.3">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="numberPassword"
android:maxLength="6"
android:layout_margin="5dp" />
</com.google.android.material.textfield.TextInputLayout>

<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Request OTP"
android:textAllCaps="false"
app:layout_constraintBottom_toTopOf="@+id/textInputET"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.95"
app:layout_constraintStart_toEndOf="@+id/textView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textInputLayout"
app:layout_constraintVertical_bias="0.0"
app:layout_constraintVertical_chainStyle="packed" />

<Button
android:id="@+id/logout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text="logout"
android:textAllCaps="false"
app:layout_constraintBaseline_toBaselineOf="@+id/button2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@+id/button2" />

<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="top" />
</androidx.constraintlayout.widget.ConstraintLayout>

the screen will be like

OTP-Token Authorization App

Kotin Code

Step #1: linking XML to Main Activity

lateinit var currentUserPhone: TextView
lateinit var otpTV: TextView
lateinit var otpET: TextInputEditText
lateinit var sendOTPbtn: Button
lateinit var verifyOTPbtn: Button
lateinit var logout: Button
lateinit var autoCompleteET: MaterialAutoCompleteTextView
private fun defineUI() {
sendOTPbtn = findViewById(R.id.button)
verifyOTPbtn = findViewById(R.id.button2)
otpTV = findViewById(R.id.textView)
otpET = findViewById(R.id.editText)
currentUserPhone = findViewById(R.id.textView4)
logout = findViewById(R.id.logout)
autoCompleteET = findViewById(R.id.outlined_exposed_dropdown_editable)
}

Step #2: define Firebase Auth and adding callbacks

lateinit var auth: FirebaseAuth
val TIME_OUT = 60
var mCallback: OnVerificationStateChangedCallbacks? = null
//.... some code in between ....//
auth = FirebaseAuth.getInstance()
mCallback = object : OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(phoneAuthCredential: PhoneAuthCredential) {
Toast.makeText(this@MainActivity, "verification completed", Toast.LENGTH_SHORT)
.show()
}

override fun onVerificationFailed(e: FirebaseException) {
Toast.makeText(this@MainActivity, "verification failed", Toast.LENGTH_SHORT).show()
Log.d("FirebaseException", e.toString())
}

override fun onCodeSent(
s: String,
forceResendingToken: ForceResendingToken
) {
super.onCodeSent(s, forceResendingToken)
verificationCode = s
Log.d("verificationCode", verificationCode)
Toast.makeText(this@MainActivity, "Code Sent", Toast.LENGTH_SHORT).show()
job = if (job == null || job!!.isCancelled)
countDown()
else {
job!!.cancel()
countDown()
}

}
}

Step #3: Implement onCLickListeners to Generate OTP button to send SMS

sendOTPbtn.setOnClickListener {
//TODO send OTP to the selected phone number
if (autoCompleteET.text != null && autoCompleteET.text.isNotEmpty())
PhoneAuthProvider.getInstance().verifyPhoneNumber(
autoCompleteET.text.toString(),// Phone number to verify
TIME_OUT.toLong(), // Timeout duration
TimeUnit.SECONDS, // Unit of timeout
this@MainActivity, // Activity (for callback binding)
mCallback!!
)
else {
hideKeyboard()
Toast
.makeText(
this@MainActivity,
"Please type phone number or pick from list",
Toast.LENGTH_SHORT
)
.show()
}

}

Moreover, for verifying OTP, we add

verifyOTPbtn.setOnClickListener {
hideKeyboard()
if (otpET.text!!.isNotEmpty()) {
val credential =
PhoneAuthProvider.getCredential(verificationCode, otpET.text.toString())
SigninWithPhone(credential)
} else {
Toast
.makeText(
this@MainActivity,
"Please type OTP number",
Toast.LENGTH_SHORT
)
.show()
}
}
private fun SigninWithPhone(credential: PhoneAuthCredential) {
auth.signInWithCredential(credential)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
Toast.makeText(this@MainActivity, "Correct OTP", Toast.LENGTH_SHORT)
.show()

} else {
Toast.makeText(this@MainActivity, "Incorrect OTP", Toast.LENGTH_SHORT)
.show()
}
}
}

Finally, set click listener on logout to sign-out from the app.

logout.setOnClickListener {
FirebaseAuth.getInstance().signOut()
}

Conclusion

In this tutorial, you learned about the firebase authentication to verify the user of your app via SMS OTP and get the user’s phone number from firebase user data. you can find the source code here from gitHub.

If you liked this post, give it a lot of claps. I’d be very grateful if you’d help it spread, sharing it on Twitter, Facebook or LinkedIn. Thank you!

--

--