Firebase Authentication is the fastest way to add a complete sign-in system to a Flutter Android app. It handles credential storage, session management, and token refresh so you don't have to. This guide walks through the full setup from dependencies to listening for auth state changes.
1. Add Dependencies
Add the required packages to pubspec.yaml:
dependencies:
firebase_core: ^3.0.0
firebase_auth: ^5.0.0
Then run:
flutter pub get
2. Connect Your App to Firebase
Download the google-services.json file from the Firebase Console and place it in android/app/.
In android/build.gradle, add the Google services plugin to the classpath:
dependencies {
classpath 'com.google.gms:google-services:4.4.1'
}
In android/app/build.gradle, apply the plugin at the bottom of the file:
apply plugin: 'com.google.gms.google-services'
3. Initialise Firebase
Before any Firebase call can be made, Firebase must be initialised. Do this once in main.dart:
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(const MyApp());
}
4. Sign Up with Email and Password
import 'package:firebase_auth/firebase_auth.dart';
final _auth = FirebaseAuth.instance;
Future<UserCredential> signUp(String email, String password) async {
return await _auth.createUserWithEmailAndPassword(
email: email,
password: password,
);
}
On success, UserCredential.user contains the newly created User object with a unique uid.
5. Sign In with Email and Password
Future<UserCredential> signIn(String email, String password) async {
return await _auth.signInWithEmailAndPassword(
email: email,
password: password,
);
}
Both signUp and signIn throw a FirebaseAuthException on failure. Wrap them in a try/catch and inspect e.code for specific error handling (user-not-found, wrong-password, email-already-in-use, etc.).
6. Sign Out
Future<void> signOut() async {
await _auth.signOut();
}
7. Listen for Auth State Changes
Rather than checking the current user on every screen, react to auth state changes with a stream. This is the idiomatic way to drive navigation between authenticated and unauthenticated flows.
StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
if (snapshot.hasData) {
return const HomeScreen();
}
return const LoginScreen();
},
)
authStateChanges() emits null when no user is signed in and a User object when one is. Wrapping your top-level MaterialApp body with this StreamBuilder gives you automatic redirects whenever the auth state flips.
What's Next
With authentication in place, the natural next step is storing extended user data beyond what Firebase Authentication provides. The UserProfile collection pattern covers how to create a matching Firestore document at sign-up and read it back across your app.