Skip to main content
Flutter Basics – Complete Beginner to Advanced Guide
CHAPTER 23 Beginner

Firebase Authentication

Updated: May 16, 2026
25 min read

# CHAPTER 23

Firebase Authentication

1. Introduction

Until now, our application has been stateless regarding identity. Every user experiences the exact same app, and data cannot be synchronized across multiple devices securely. Building a custom backend server to handle hashed passwords, security tokens, and email verification is incredibly complex and dangerous if done incorrectly. Enter Firebase, Google's Backend-as-a-Service (BaaS) platform. Firebase provides secure, pre-built infrastructure for authentication, databases, storage, and analytics. In this chapter, we will master Firebase Authentication. We will connect our Android project to the Firebase Console, implement secure Email and Password registration, manage active user sessions, and build a robust login architecture.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Connect an Android Studio project to a Google Firebase project.
  • Configure the google-services.json file and Gradle dependencies.
  • Implement the Email/Password User Registration flow.
  • Implement the User Sign-In and Sign-Out functionality.
  • Check the current session state to route users to the Dashboard or the Login screen.
  • Handle Firebase asynchronous Tasks and Exceptions gracefully.

3. Step 1: Connecting to Firebase

Before writing code, we must register our app with Google.
  1. 1. Go to the Firebase Console in your browser.
  1. 2. Click "Add Project", name it (e.g., "KotlinCourseApp"), and disable Google Analytics for now.
  1. 3. Once created, click the Android Icon to add an app.
  1. 4. Enter your Android Package Name (found at the top of your MainActivity.kt, e.g., com.example.myapp).
  1. 5. Download the google-services.json file.
  1. 6. Switch Android Studio to "Project" view and drag the google-services.json file directly into the app folder.

4. Step 2: Gradle Configuration

Firebase requires specific Google Services plugins to read the JSON file.

In your project-level build.gradle.kts (or build.gradle): Add the Google Services dependency inside buildscript { dependencies { ... } } or in the plugins block depending on your Gradle version.

kotlin
123
plugins {
    id("com.google.gms.google-services") version "4.4.1" apply false
}

In your app-level build.gradle.kts (Module :app): Apply the plugin at the top, and add the Authentication dependency:

kotlin
1234567891011
plugins {
    id("com.google.gms.google-services")
}

dependencies {
    // Import the Firebase BoM (Bill of Materials) for version management
    implementation(platform("com.google.firebase:firebase-bom:32.7.1"))
    
    // Declare the dependency for Firebase Authentication
    implementation("com.google.firebase:firebase-auth")
}

*Click "Sync Now"!* Finally, go back to the Firebase Console in your browser, click Authentication -> Get Started, and explicitly enable the Email/Password sign-in provider.

5. Step 3: Registering a New User (Sign Up)

Firebase handles all password hashing and server communication in the background. We simply pass it an email and password using the FirebaseAuth instance.
kotlin
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.firebase.auth.FirebaseAuth

class RegisterActivity : AppCompatActivity() {

    // 1. Declare the Auth instance
    private lateinit var auth: FirebaseAuth

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

        // 2. Initialize Firebase Auth
        auth = FirebaseAuth.getInstance()

        val emailInput = findViewById<EditText>(R.id.emailInput)
        val passwordInput = findViewById<EditText>(R.id.passwordInput)
        val registerBtn = findViewById<Button>(R.id.registerBtn)

        registerBtn.setOnClickListener {
            val email = emailInput.text.toString().trim()
            val password = passwordInput.text.toString().trim()

            // Firebase requires passwords to be at least 6 characters!
            if (email.isNotEmpty() && password.length >= 6) {
                
                // 3. Call the Firebase creation function
                auth.createUserWithEmailAndPassword(email, password)
                    .addOnCompleteListener(this) { task ->
                        if (task.isSuccessful) {
                            // Success! The user is registered and logged in.
                            val user = auth.currentUser
                            Toast.makeText(this, "Welcome ${user?.email}!", Toast.LENGTH_SHORT).show()
                            // TODO: Navigate to Dashboard Activity
                        } else {
                            // Failure (e.g., Email already in use, bad format)
                            Toast.makeText(this, "Error: ${task.exception?.message}", Toast.LENGTH_LONG).show()
                        }
                    }
            }
        }
    }
}

6. Step 4: Signing In an Existing User

The logic for logging in is nearly identical, utilizing signInWithEmailAndPassword.
kotlin
12345678910111213141516
loginBtn.setOnClickListener {
    val email = emailInput.text.toString().trim()
    val password = passwordInput.text.toString().trim()

    auth.signInWithEmailAndPassword(email, password)
        .addOnCompleteListener(this) { task ->
            if (task.isSuccessful) {
                // Success!
                Toast.makeText(this, "Login Successful!", Toast.LENGTH_SHORT).show()
                // Navigate to Dashboard
            } else {
                // Failure (e.g., Wrong password, user doesn't exist)
                Toast.makeText(this, "Login Failed: ${task.exception?.message}", Toast.LENGTH_LONG).show()
            }
        }
}

7. Step 5: Session Management (Routing)

When a user closes the app and reopens it, they shouldn't have to log in again. Firebase automatically saves a secure session token locally. In your SplashActivity or MainActivity, check if a currentUser exists. If they exist, skip the login screen!
kotlin
1234567891011
override fun onStart() {
    super.onStart()
    
    val currentUser = auth.currentUser
    if (currentUser != null) {
        // User is already signed in! Navigate directly to the Dashboard.
        val intent = Intent(this, DashboardActivity::class.java)
        startActivity(intent)
        finish() // Destroy the Login activity so they can't press "Back" to get to it
    }
}

8. Step 6: Signing Out

Signing out destroys the local session token.
kotlin
12345678
logoutButton.setOnClickListener {
    FirebaseAuth.getInstance().signOut()
    
    // Send them back to the Login Screen
    val intent = Intent(this, LoginActivity::class.java)
    startActivity(intent)
    finish()
}

9. Firebase Coroutines (Advanced)

Firebase Tasks (addOnCompleteListener) use standard callbacks, which can lead to nested "Callback Hell". Modern Android architecture uses Coroutines. The kotlinx-coroutines-play-services library provides .await(), allowing you to execute Firebase calls sequentially inside viewModelScope.

*(Requires: implementation("org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.7.3"))*

kotlin
123456789
viewModelScope.launch {
    try {
        // The coroutine pauses here until Firebase finishes! No callbacks!
        val result = auth.signInWithEmailAndPassword(email, password).await()
        println("Success: ${result.user?.email}")
    } catch (e: Exception) {
        println("Error: ${e.message}")
    }
}

10. Common Mistakes

  • Forgetting to Enable the Provider: Spending 3 hours debugging code because createUserWithEmailAndPassword throws an error, only to realize you never clicked the toggle to enable "Email/Password" inside the Firebase Web Console.
  • Leaking the Login Screen: Using startActivity to go to the Dashboard without calling finish(). If the user hits the physical back button on their phone, they will return to the Login screen despite being fully logged in!

11. Best Practices

  • UX Feedback: Firebase network calls take 1–3 seconds. Always show a ProgressBar when the user clicks "Submit", and disable the button to prevent them from clicking it 5 times and initiating 5 simultaneous network requests.

12. Exercises

  1. 1. Setup a Firebase project and successfully sync the google-services.json with an empty Android app.
  1. 2. Build a simple UI with two EditTexts and a "Register" button. Implement the Firebase Registration logic.

13. Coding Challenges

Challenge: Implement "Password Reset" functionality. Research the auth.sendPasswordResetEmail(email) method. Create a "Forgot Password?" button that extracts the email from the EditText and sends a Firebase password reset link, displaying a Toast on success.

14. MCQ Quiz with Answers

Question 1

What critical functional role does the google-services.json file play in the Firebase Authentication architecture?

Question 2

When designing the initial application routing logic within onStart(), how does a developer definitively ascertain if an active user session persists from a previous application launch?

15. Interview Questions

  • Q: Explain the structural hazards of utilizing traditional nested Callbacks (addOnCompleteListener) for Firebase authentication logic within a robust MVVM architecture. How does utilizing Coroutines and the .await() extension function mitigate these issues?
  • Q: Detail the user experience (UX) and architectural imperatives of utilizing finish() or Intent flag manipulation (FLAG_ACTIVITY_CLEAR_TASK) immediately following a successful Firebase login execution.
  • Q: Describe how Firebase manages session persistence. Under what programmatic conditions is the local authentication token invalidated?

16. Summary

In Chapter 23, we established identity within our application by integrating Firebase Authentication. We successfully bridged our Android project to the Google Cloud backend utilizing the Google Services JSON manifest. We engineered secure Registration and Login workflows utilizing Email and Password protocols, mitigating the complex liabilities of custom server hashing. Furthermore, we implemented intelligent routing architectures by evaluating persistent Session Tokens to bypass authentication screens for returning users, ensuring a seamless, modern user experience.

17. Next Chapter Recommendation

Now that we have authenticated users, we need to save their profile data, high scores, and social posts to the cloud. We cannot use Room, as that is restricted to the local device. Proceed to Chapter 24: Firebase Cloud Firestore to master remote, real-time NoSQL database integration.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·