To use Firebase Auth with Flutter, add the FlutterFire packages (firebase_core and firebase_auth) to your project and run the FlutterFire CLI to auto-generate platform configuration. Use StreamBuilder with FirebaseAuth.instance.authStateChanges() to reactively rebuild the UI when the user signs in or out. Firebase Auth in Flutter supports email/password, Google Sign-In, Apple Sign-In, phone authentication, and anonymous auth out of the box.
Implementing Firebase Authentication in Flutter
FlutterFire provides official Firebase plugins for Flutter that work across iOS, Android, web, and desktop. This tutorial walks through configuring Firebase in a Flutter project using the FlutterFire CLI, implementing email/password authentication with sign-up and login screens, reacting to auth state changes with StreamBuilder, and adding Google Sign-In as an OAuth provider. You will build a complete auth flow that persists user sessions and handles errors gracefully.
Prerequisites
- Flutter SDK 3.x+ installed with a working development environment
- A Firebase project created in the Firebase Console
- FlutterFire CLI installed (dart pub global activate flutterfire_cli)
- Email/Password sign-in enabled in Firebase Console > Authentication > Sign-in method
Step-by-step guide
Configure Firebase with the FlutterFire CLI
Configure Firebase with the FlutterFire CLI
The FlutterFire CLI auto-generates platform-specific configuration files so you do not need to manually add google-services.json or GoogleService-Info.plist. Run flutterfire configure in your project root, select your Firebase project, and choose the platforms you want to configure. The CLI creates a firebase_options.dart file with your Firebase config.
1# Install FlutterFire CLI2dart pub global activate flutterfire_cli34# Run configuration (select your Firebase project)5flutterfire configure67# Add Firebase packages to pubspec.yaml8flutter pub add firebase_core firebase_authExpected result: A lib/firebase_options.dart file is generated with platform-specific configuration for your Firebase project.
Initialize Firebase in your app
Initialize Firebase in your app
Call Firebase.initializeApp() in your main() function before running the app. Pass the DefaultFirebaseOptions from the generated firebase_options.dart file. This must complete before any Firebase service is used.
1import 'package:firebase_core/firebase_core.dart';2import 'package:flutter/material.dart';3import 'firebase_options.dart';45void main() async {6 WidgetsFlutterBinding.ensureInitialized();7 await Firebase.initializeApp(8 options: DefaultFirebaseOptions.currentPlatform,9 );10 runApp(const MyApp());11}Expected result: Firebase is initialized and all Firebase services (Auth, Firestore, etc.) are available throughout the app.
Implement email/password sign-up and sign-in
Implement email/password sign-up and sign-in
Use FirebaseAuth.instance to access auth methods. createUserWithEmailAndPassword() registers new users, and signInWithEmailAndPassword() logs in existing users. Both return a UserCredential containing the User object. Wrap calls in try-catch to handle errors like weak-password, email-already-in-use, and wrong-password.
1import 'package:firebase_auth/firebase_auth.dart';23class AuthService {4 final FirebaseAuth _auth = FirebaseAuth.instance;56 Future<String?> signUp(String email, String password) async {7 try {8 await _auth.createUserWithEmailAndPassword(9 email: email,10 password: password,11 );12 return null; // success13 } on FirebaseAuthException catch (e) {14 return e.message; // return error message15 }16 }1718 Future<String?> signIn(String email, String password) async {19 try {20 await _auth.signInWithEmailAndPassword(21 email: email,22 password: password,23 );24 return null;25 } on FirebaseAuthException catch (e) {26 return e.message;27 }28 }2930 Future<void> signOut() async {31 await _auth.signOut();32 }3334 User? get currentUser => _auth.currentUser;35}Expected result: Users can create accounts and sign in with email and password, with errors returned as human-readable messages.
React to auth state changes with StreamBuilder
React to auth state changes with StreamBuilder
FirebaseAuth.instance.authStateChanges() returns a Stream that emits the current User whenever the auth state changes (sign in, sign out, token refresh). Use StreamBuilder at the top of your widget tree to switch between authentication screens and the main app based on the current user.
1import 'package:firebase_auth/firebase_auth.dart';2import 'package:flutter/material.dart';34class AuthGate extends StatelessWidget {5 const AuthGate({super.key});67 @override8 Widget build(BuildContext context) {9 return StreamBuilder<User?>(10 stream: FirebaseAuth.instance.authStateChanges(),11 builder: (context, snapshot) {12 // Show loading indicator while checking auth state13 if (snapshot.connectionState == ConnectionState.waiting) {14 return const Scaffold(15 body: Center(child: CircularProgressIndicator()),16 );17 }1819 // User is signed in20 if (snapshot.hasData) {21 return const HomeScreen();22 }2324 // User is not signed in25 return const LoginScreen();26 },27 );28 }29}Expected result: The app automatically navigates between login and home screens when the user signs in or out.
Add Google Sign-In
Add Google Sign-In
Google Sign-In requires the google_sign_in package for the native flow and GoogleAuthProvider from firebase_auth. The user signs in with Google first (which shows the native account picker), then the Google credential is used to authenticate with Firebase. Enable Google as a sign-in provider in the Firebase Console.
1import 'package:google_sign_in/google_sign_in.dart';2import 'package:firebase_auth/firebase_auth.dart';34Future<String?> signInWithGoogle() async {5 try {6 // Trigger the Google Sign-In flow7 final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn();8 if (googleUser == null) return 'Sign-in cancelled';910 // Get auth details from the Google account11 final GoogleSignInAuthentication googleAuth =12 await googleUser.authentication;1314 // Create a Firebase credential15 final credential = GoogleAuthProvider.credential(16 accessToken: googleAuth.accessToken,17 idToken: googleAuth.idToken,18 );1920 // Sign in to Firebase with the Google credential21 await FirebaseAuth.instance.signInWithCredential(credential);22 return null; // success23 } catch (e) {24 return e.toString();25 }26}2728// Add to pubspec.yaml: google_sign_in: ^6.0.0Expected result: Users can sign in with their Google account using the native account picker, and the session is managed by Firebase Auth.
Protect routes and display user info
Protect routes and display user info
Once authenticated, access the current user's information through FirebaseAuth.instance.currentUser. Use this to display the user's email, name, or photo, and to protect screens that require authentication. The User object provides uid, email, displayName, photoURL, and emailVerified properties.
1import 'package:firebase_auth/firebase_auth.dart';2import 'package:flutter/material.dart';34class HomeScreen extends StatelessWidget {5 const HomeScreen({super.key});67 @override8 Widget build(BuildContext context) {9 final user = FirebaseAuth.instance.currentUser!;1011 return Scaffold(12 appBar: AppBar(13 title: const Text('Home'),14 actions: [15 IconButton(16 icon: const Icon(Icons.logout),17 onPressed: () => FirebaseAuth.instance.signOut(),18 ),19 ],20 ),21 body: Center(22 child: Column(23 mainAxisAlignment: MainAxisAlignment.center,24 children: [25 if (user.photoURL != null)26 CircleAvatar(27 backgroundImage: NetworkImage(user.photoURL!),28 radius: 40,29 ),30 const SizedBox(height: 16),31 Text('Welcome, ${user.displayName ?? user.email}'),32 Text('UID: ${user.uid}'),33 ],34 ),35 ),36 );37 }38}Expected result: The home screen displays the authenticated user's name, photo, and UID with a sign-out button.
Complete working example
1import 'package:firebase_auth/firebase_auth.dart';2import 'package:google_sign_in/google_sign_in.dart';34class AuthService {5 final FirebaseAuth _auth = FirebaseAuth.instance;67 // Auth state stream for StreamBuilder8 Stream<User?> get authStateChanges => _auth.authStateChanges();910 // Current user (may be null)11 User? get currentUser => _auth.currentUser;1213 // Email/password sign-up14 Future<String?> signUp(String email, String password) async {15 try {16 await _auth.createUserWithEmailAndPassword(17 email: email,18 password: password,19 );20 return null;21 } on FirebaseAuthException catch (e) {22 return _mapErrorCode(e.code);23 }24 }2526 // Email/password sign-in27 Future<String?> signIn(String email, String password) async {28 try {29 await _auth.signInWithEmailAndPassword(30 email: email,31 password: password,32 );33 return null;34 } on FirebaseAuthException catch (e) {35 return _mapErrorCode(e.code);36 }37 }3839 // Google Sign-In40 Future<String?> signInWithGoogle() async {41 try {42 final googleUser = await GoogleSignIn().signIn();43 if (googleUser == null) return 'Sign-in cancelled.';4445 final googleAuth = await googleUser.authentication;46 final credential = GoogleAuthProvider.credential(47 accessToken: googleAuth.accessToken,48 idToken: googleAuth.idToken,49 );5051 await _auth.signInWithCredential(credential);52 return null;53 } catch (e) {54 return e.toString();55 }56 }5758 // Sign out59 Future<void> signOut() async {60 await GoogleSignIn().signOut();61 await _auth.signOut();62 }6364 // Map error codes to user-friendly messages65 String _mapErrorCode(String code) {66 switch (code) {67 case 'weak-password':68 return 'Password must be at least 6 characters.';69 case 'email-already-in-use':70 return 'An account with this email already exists.';71 case 'invalid-email':72 return 'Please enter a valid email address.';73 case 'user-not-found':74 return 'No account found with this email.';75 case 'wrong-password':76 return 'Incorrect password. Please try again.';77 default:78 return 'An error occurred. Please try again.';79 }80 }81}Common mistakes when using Firebase Auth with Flutter
Why it's a problem: Forgetting to call WidgetsFlutterBinding.ensureInitialized() before Firebase.initializeApp() in main()
How to avoid: Add WidgetsFlutterBinding.ensureInitialized() as the first line in main() before any async operations.
Why it's a problem: Not running flutterfire configure after changing Firebase project settings or adding platforms
How to avoid: Run flutterfire configure again whenever your Firebase project settings change. This regenerates firebase_options.dart.
Why it's a problem: Using currentUser directly in the widget tree instead of authStateChanges() with StreamBuilder
How to avoid: currentUser can be null during initialization. Use StreamBuilder with authStateChanges() for reactive, reliable auth state handling.
Why it's a problem: Not adding SHA-1 fingerprint for Android Google Sign-In, causing authentication to fail silently
How to avoid: Generate your debug SHA-1 with 'keytool -list -v -keystore ~/.android/debug.keystore' and add it in Firebase Console > Project Settings > Your Apps > Android.
Best practices
- Use the FlutterFire CLI (flutterfire configure) for automatic platform configuration instead of manual setup
- Create an AuthService class to encapsulate all authentication logic and keep widgets clean
- Use StreamBuilder with authStateChanges() at the top of the widget tree for reactive auth routing
- Map FirebaseAuthException error codes to user-friendly messages instead of showing raw error strings
- Sign out of both Google and Firebase when implementing Google Sign-In sign-out
- Enable only the sign-in providers you actually use in the Firebase Console to reduce attack surface
- Test on both iOS and Android since platform-specific configuration differs (SHA-1, URL schemes)
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
Build Firebase Auth for a Flutter app. Show FlutterFire CLI setup, email/password sign-up and sign-in, authStateChanges with StreamBuilder, Google Sign-In with the google_sign_in package, error handling with user-friendly messages, and a sign-out flow.
Create a Flutter AuthService class with Firebase Auth. Include email/password signup, signin, Google Sign-In, signOut, authStateChanges stream, and error code mapping. Use firebase_auth 5.x+ and google_sign_in. Also show the StreamBuilder auth gate widget.
Frequently asked questions
Do I need to manually add google-services.json and GoogleService-Info.plist?
No. The FlutterFire CLI (flutterfire configure) automatically generates and places these files. You only need to run the CLI and select your platforms.
Does Firebase Auth persist the login session in Flutter?
Yes. Firebase Auth automatically persists the session to secure storage on mobile devices. When the app restarts, the user remains signed in until they explicitly sign out.
How do I add Apple Sign-In to my Flutter app?
Add the sign_in_with_apple package, enable Apple as a sign-in provider in Firebase Console, configure your Apple Developer account with a Service ID, and use AppleAuthProvider with signInWithProvider().
What is the difference between authStateChanges and idTokenChanges?
authStateChanges emits when the user signs in or out. idTokenChanges also emits when the ID token is refreshed (e.g., after custom claims change). Use idTokenChanges if you need to react to token updates.
Can I use Firebase Auth without the FlutterFire CLI?
Yes, but it requires manual setup: downloading google-services.json, modifying build.gradle for Android, adding GoogleService-Info.plist to Xcode, and configuring each platform individually. The CLI automates all of this.
Can RapidDev help build a Flutter app with Firebase authentication?
Yes. RapidDev can implement complete authentication flows in Flutter including email/password, social login, phone auth, and role-based access control with Firestore custom claims.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation