Set Up Firebase Phone Authentication in Jetpack Compose Easily

Firebase Phone Authentication is a powerful and secure way to verify users in your Android app. With Jetpack Compose, Google’s modern UI toolkit, implementing this feature becomes even more efficient and seamless. This comprehensive guide will walk you through setting up Firebase Phone Authentication in a Jetpack Compose project, ensuring you’re equipped with advanced tips, best practices, and deep technical insights.

Why Use Firebase Phone Authentication?

Firebase Phone Authentication is a convenient, secure, and scalable method to validate users based on their phone numbers. It’s particularly useful for:

  • Simplifying user sign-up/sign-in: No need for complex passwords.

  • Improving security: Firebase handles verification and backend operations.

  • Enhancing user experience: Quick OTP-based authentication reduces friction.

Combined with Jetpack Compose’s declarative UI approach, you can create a robust and user-friendly authentication flow.

Prerequisites

Before diving in, ensure you have the following:

  1. Android Studio Bumblebee (2021.1.1) or later installed.

  2. Firebase project setup:

    • Add your app’s SHA-1 and SHA-256 fingerprints.

    • Enable Phone Authentication in the Firebase Console.

  3. Basic understanding of Jetpack Compose.

Step 1: Add Dependencies

To use Firebase in your Jetpack Compose project, add the required dependencies to your build.gradle files.

Project-level build.gradle:

classpath 'com.google.gms:google-services:4.3.15'

App-level build.gradle:

plugins {
    id 'com.android.application'
    id 'com.google.gms.google-services'
}

dependencies {
    implementation platform('com.google.firebase:firebase-bom:32.1.1')
    implementation 'com.google.firebase:firebase-auth'
}

Sync your project to ensure dependencies are properly added.

Step 2: Initialize Firebase

In your app’s Application class or MainActivity, initialize Firebase.

Example:

import android.app.Application
import com.google.firebase.FirebaseApp

class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        FirebaseApp.initializeApp(this)
    }
}

Update your AndroidManifest.xml to include this application class:

<application
    android:name=".MyApp"
    ... >
</application>

Step 3: Design the UI with Jetpack Compose

Jetpack Compose simplifies UI creation with a declarative approach. Let’s design the phone authentication screens.

3.1 Input Phone Number

Create a composable for entering the phone number.

@Composable
fun PhoneNumberInputScreen(onSubmit: (String) -> Unit) {
    var phoneNumber by remember { mutableStateOf("") }

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        TextField(
            value = phoneNumber,
            onValueChange = { phoneNumber = it },
            label = { Text("Enter Phone Number") },
            keyboardOptions = KeyboardOptions.Default.copy(
                keyboardType = KeyboardType.Phone
            )
        )
        Spacer(modifier = Modifier.height(16.dp))
        Button(onClick = { onSubmit(phoneNumber) }) {
            Text("Submit")
        }
    }
}

3.2 Verify OTP

Create another composable for OTP verification.

@Composable
fun OtpVerificationScreen(onVerify: (String) -> Unit) {
    var otp by remember { mutableStateOf("") }

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        TextField(
            value = otp,
            onValueChange = { otp = it },
            label = { Text("Enter OTP") },
            keyboardOptions = KeyboardOptions.Default.copy(
                keyboardType = KeyboardType.Number
            )
        )
        Spacer(modifier = Modifier.height(16.dp))
        Button(onClick = { onVerify(otp) }) {
            Text("Verify")
        }
    }
}

Step 4: Implement Phone Authentication Logic

4.1 Request OTP

Use Firebase Authentication to send the OTP.

import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.PhoneAuthProvider
import java.util.concurrent.TimeUnit

fun sendOtp(phoneNumber: String, callbacks: PhoneAuthProvider.OnVerificationStateChangedCallbacks) {
    val options = PhoneAuthProvider.verifyPhoneNumberOptions {
        setPhoneNumber(phoneNumber)
        setTimeout(60L, TimeUnit.SECONDS)
        setActivity(context as Activity)
        setCallbacks(callbacks)
    }
    PhoneAuthProvider.verifyPhoneNumber(options)
}

4.2 Verify OTP

Authenticate the user with the OTP.

fun verifyOtp(verificationId: String, otp: String, onSuccess: () -> Unit, onFailure: (Exception) -> Unit) {
    val credential = PhoneAuthProvider.getCredential(verificationId, otp)
    FirebaseAuth.getInstance().signInWithCredential(credential)
        .addOnCompleteListener { task ->
            if (task.isSuccessful) {
                onSuccess()
            } else {
                onFailure(task.exception ?: Exception("Unknown Error"))
            }
        }
}

Step 5: Combine UI and Logic

Integrate the UI with the authentication logic for a seamless experience.

@Composable
fun AuthenticationFlow() {
    var currentScreen by remember { mutableStateOf("PhoneInput") }
    var verificationId by remember { mutableStateOf("") }

    when (currentScreen) {
        "PhoneInput" -> PhoneNumberInputScreen { phoneNumber ->
            sendOtp(phoneNumber, object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
                override fun onVerificationCompleted(credential: PhoneAuthCredential) {
                    // Auto-retrieved OTP success
                }

                override fun onVerificationFailed(e: FirebaseException) {
                    // Handle error
                }

                override fun onCodeSent(id: String, token: PhoneAuthProvider.ForceResendingToken) {
                    verificationId = id
                    currentScreen = "OtpVerification"
                }
            })
        }
        "OtpVerification" -> OtpVerificationScreen { otp ->
            verifyOtp(verificationId, otp, onSuccess = {
                // Navigate to the main app
            }, onFailure = {
                // Show error
            })
        }
    }
}

Best Practices

  • Secure Your API Keys: Use Firebase App Check to prevent abuse.

  • Handle Errors Gracefully: Display user-friendly messages for authentication errors.

  • Test Thoroughly: Test on real devices with various network conditions.

Conclusion

Setting up Firebase Phone Authentication in Jetpack Compose simplifies the authentication flow while leveraging Compose’s declarative UI framework. By following this guide, you’ll implement a robust, user-friendly authentication system that enhances your app’s user experience. Combine Firebase’s powerful features with Jetpack Compose’s flexibility to create modern, secure, and scalable apps.

Start integrating Firebase Phone Authentication in your Jetpack Compose projects today, and give your users a seamless onboarding experience!