Phone Authentication using Android with Firebase

Phone Authentication in Android with Firebase: Complete Tutorial (2026) | D.Tech Academic

Phone Authentication in Android with Firebase: Complete Tutorial (2026)

Last Updated: | Author: Deep Singh

Phone number authentication is one of the most convenient login methods for mobile apps. Users type their phone number, receive an SMS with a one-time password (OTP), enter it, and they're logged in — no password to remember, no email verification loop.

In this tutorial, you'll implement Firebase Phone Authentication in Android from scratch. We'll walk through creating a Firebase project, enabling phone sign-in, wiring up the Gradle dependencies, and building a working login screen with OTP verification.

Output Screens

The final app has a login screen with a mobile number input and an OTP input field, plus a home page that shows the signed-in user and a logout button.

Creating a Firebase Project

Open the Firebase Console and sign in with your Google account. Click Add Project, give it a name (e.g., Phone Authentication), and follow the wizard.

Once the project is created, register your Android app by entering the package name from your AndroidManifest.xml. Download the generated google-services.json file — you'll need to place it in your project shortly.

Enabling Phone Authentication

In the Firebase Console, navigate to Authentication → Sign-in method. Enable the Phone sign-in provider. If you want, you can also enable Email/Password or other providers at the same time.

Important: Firebase requires your app's SHA-1 fingerprint to enable phone authentication. You can get it by running ./gradlew signingReport in Android Studio's Terminal, then copy the SHA-1 value into your Firebase project settings.

Configuring Android Studio

In your app-level build.gradle, add the Firebase Auth dependency:

dependencies {
    // Use the Firebase BoM so all Firebase libraries align
    implementation platform('com.google.firebase:firebase-bom:33.5.1')
    implementation 'com.google.firebase:firebase-auth'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
}

And apply the Google Services plugin at the bottom of the file:

apply plugin: 'com.google.gms.google-services'

Also make sure your project-level build.gradle includes the Google Services classpath:

buildscript {
    dependencies {
        classpath 'com.google.gms:google-services:4.4.2'
    }
}

Place google-services.json inside app/ in your project, and sync Gradle.

Note on versions: The original tutorial used firebase-auth:16.0.5. That version is several years old and doesn't work with modern Flutter or Firebase BoM setups. Use the BoM approach shown above.

Layouts

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"
        android:src="@drawable/back_document" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@id/ll"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="70dp"
        android:text="Phone Authentication"
        android:textColor="#fff"
        android:textSize="30sp"
        android:textStyle="bold"
        android:typeface="serif" />

    <LinearLayout
        android:id="@+id/ll"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:orientation="vertical">

        <EditText
            android:id="@+id/mymobile"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20dp"
            android:layout_marginTop="20dp"
            android:layout_marginRight="20dp"
            android:background="@drawable/button"
            android:hint="Enter Mobile Number"
            android:inputType="number"
            android:maxLength="10"
            android:padding="20dp"
            android:textColor="#fff"
            android:textColorHint="#fff" />

        <EditText
            android:id="@+id/myotp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20dp"
            android:layout_marginTop="20dp"
            android:layout_marginRight="20dp"
            android:background="@drawable/button"
            android:hint="OTP Number"
            android:inputType="number"
            android:maxLength="6"
            android:padding="20dp"
            android:textColor="#fff"
            android:textColorHint="#fff" />

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20dp"
            android:layout_marginTop="50dp"
            android:layout_marginRight="20dp"
            android:background="@drawable/button"
            android:onClick="generate"
            android:text="Generate"
            android:textAllCaps="false"
            android:textColor="#fff"
            android:textStyle="bold"
            android:typeface="serif" />

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="20dp"
            android:layout_marginTop="20dp"
            android:layout_marginRight="20dp"
            android:background="@drawable/button"
            android:onClick="verify"
            android:text="Verify & Login"
            android:textAllCaps="false"
            android:textColor="#fff"
            android:textStyle="bold"
            android:typeface="serif" />

    </LinearLayout>

</RelativeLayout>

activity_home_page.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"
        android:src="@drawable/back_document" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:padding="20dp"
        android:text="Welcome To Home Page"
        android:textColor="#fff"
        android:textSize="20sp"
        android:textStyle="italic"
        android:typeface="serif" />

    <TextView
        android:id="@+id/mytext"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerInParent="true"
        android:padding="20dp"
        android:textColor="#fff"
        android:textSize="20sp"
        android:typeface="serif" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:layout_marginBottom="20dp"
        android:background="@drawable/button"
        android:onClick="logout"
        android:text="Logout"
        android:textColor="#fff"
        android:textStyle="bold" />

</RelativeLayout>

drawable/button.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <stroke
        android:width="1dp"
        android:color="#fff" />
    <corners
        android:bottomRightRadius="10dp"
        android:topLeftRadius="10dp" />
</shape>

MainActivity.java

package com.example.phoneauthentication;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.FirebaseException;
import com.google.firebase.auth.AuthResult;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.auth.PhoneAuthCredential;
import com.google.firebase.auth.PhoneAuthProvider;

import java.util.concurrent.TimeUnit;

public class MainActivity extends AppCompatActivity {

    private EditText tmobile, totp;
    private PhoneAuthProvider.OnVerificationStateChangedCallbacks myCallbacks;
    private FirebaseAuth mAuth;
    private String verificationCode;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tmobile = findViewById(R.id.mymobile);
        totp = findViewById(R.id.myotp);
        firebaseLogin();
    }

    /**
     * Called by the "Generate" button. Sends an OTP to the entered
     * phone number.
     */
    public void generate(View view) {
        String phone = tmobile.getText().toString().trim();
        if (phone.isEmpty() || phone.length() < 10) {
            Toast.makeText(this, "Enter a valid 10-digit mobile number", Toast.LENGTH_SHORT).show();
            return;
        }

        PhoneAuthProvider.getInstance().verifyPhoneNumber(
                "+91" + phone,          // Phone number with country code
                60,                     // Timeout duration
                TimeUnit.SECONDS,       // Timeout unit
                this,                   // Activity for callback
                myCallbacks             // Callback handler
        );
    }

    /**
     * Called by the "Verify & Login" button. Verifies the code entered
     * by the user against the code Firebase sent via SMS.
     */
    public void verify(View view) {
        String otp = totp.getText().toString().trim();
        if (otp.isEmpty()) {
            Toast.makeText(this, "Enter the OTP", Toast.LENGTH_SHORT).show();
            return;
        }

        PhoneAuthCredential credential =
                PhoneAuthProvider.getCredential(verificationCode, otp);
        signInWithPhone(credential);
    }

    private void firebaseLogin() {
        mAuth = FirebaseAuth.getInstance();
        myCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() {

            @Override
            public void onVerificationCompleted(@NonNull PhoneAuthCredential credential) {
                // Auto-retrieval succeeded — sign in directly
                Log.d("PhoneAuth", "Auto-verification succeeded");
                totp.setText(credential.getSmsCode());
                signInWithPhone(credential);
            }

            @Override
            public void onVerificationFailed(@NonNull FirebaseException e) {
                Log.e("PhoneAuth", "Verification failed", e);
                Toast.makeText(MainActivity.this,
                        "Verification failed: " + e.getMessage(),
                        Toast.LENGTH_LONG).show();
            }

            @Override
            public void onCodeSent(@NonNull String s,
                                   @NonNull PhoneAuthProvider.ForceResendingToken token) {
                super.onCodeSent(s, token);
                verificationCode = s;
                Log.d("PhoneAuth", "OTP sent. verificationId = " + s);
                Toast.makeText(MainActivity.this,
                        "OTP sent to your phone",
                        Toast.LENGTH_SHORT).show();
            }
        };
    }

    private void signInWithPhone(PhoneAuthCredential credential) {
        mAuth.signInWithCredential(credential)
                .addOnCompleteListener(new OnCompleteListener<AuthResult>() {
                    @Override
                    public void onComplete(@NonNull Task<AuthResult> task) {
                        if (task.isSuccessful()) {
                            Toast.makeText(MainActivity.this,
                                    "Signed in successfully",
                                    Toast.LENGTH_SHORT).show();
                            goToHomePage();
                        } else {
                            Toast.makeText(MainActivity.this,
                                    "Sign-in failed: " + task.getException(),
                                    Toast.LENGTH_LONG).show();
                        }
                    }
                });
    }

    @Override
    protected void onStart() {
        super.onStart();
        FirebaseUser user = mAuth.getCurrentUser();
        if (user != null) {
            goToHomePage();
        }
    }

    private void goToHomePage() {
        startActivity(new Intent(MainActivity.this, HomePage.class));
        finish();
    }
}

HomePage.java

package com.example.phoneauthentication;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;

public class HomePage extends AppCompatActivity {

    private FirebaseAuth mAuth;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home_page);

        mAuth = FirebaseAuth.getInstance();

        TextView ttext = findViewById(R.id.mytext);
        FirebaseUser user = mAuth.getCurrentUser();
        if (user != null) {
            String displayName = user.getDisplayName() != null
                    ? user.getDisplayName()
                    : "User";
            String email = user.getEmail() != null
                    ? user.getEmail()
                    : "No email";
            String phone = user.getPhoneNumber() != null
                    ? user.getPhoneNumber()
                    : "No phone";
            ttext.setText(displayName + "\n" + email + "\n" + phone);
        }
    }

    public void logout(View view) {
        mAuth.signOut();
        startActivity(new Intent(this, MainActivity.class));
        finish();
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.phoneauthentication">

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity android:name=".HomePage" />
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>

</manifest>

Common Pitfalls

  • Missing SHA-1 fingerprint. Without it, Firebase will refuse to send an OTP. Register both your debug and release SHA-1 in the Firebase Console.
  • Test numbers during development. Firebase lets you add test phone numbers and codes in the Console → Authentication → Sign-in method → Phone → Phone numbers for testing. Use them to avoid hitting SMS quotas.
  • Wrong phone number format. Firebase needs the country code (e.g., +91 for India). If you forget it, verification will fail silently.
  • Auto-retrieval can fire on emulators. The onVerificationCompleted callback may fire before you've entered anything, so it's safe to also fill the OTP field automatically (as shown).
  • Expired verification IDs. The verificationId returned in onCodeSent is only valid for a limited time (typically the timeout you set). If you wait too long, verification fails.
  • Using old Firebase SDKs. The firebase-auth:16.0.5 version from 2018 tutorials is not compatible with current Android Gradle Plugin versions. Use the Firebase BoM approach.
  • Forgetting to call Firebase.initializeApp(). The plugin auto-initialises from google-services.json, but if you've moved to a manual setup, you must call it explicitly in your Application class.
  • Not handling the onStart auto-login check. If a user is already signed in, they should skip the login screen. The example does this in onStart.

Wrapping Up

You now have a working Firebase Phone Authentication flow in Android. Users enter their phone number, Firebase sends an OTP, they verify it, and they're logged in. The HomePage shows the signed-in user and includes a logout button.

From here, you can extend the app with:

  • Resend OTP. Use the ForceResendingToken from onCodeSent to allow resending without a full restart.
  • Multiple auth providers. Combine phone auth with Google Sign-In or email/password for a complete authentication system.
  • Firestore integration. Store user profile data linked to the Firebase UID after sign-in.
  • Modern UI. Replace the plain EditText/Button layout with Material 3 components or Jetpack Compose for a cleaner look.
  • Test phone numbers. Add fake numbers in the Firebase Console so you can test freely without burning SMS quota.