image

06 Jan 2026

9K

35K

Flutter & Firebase Auth: Automating Email Verification

Email verification is a critical security measure for any application, ensuring that users provide a valid email address and preventing unauthorized access or spam. When building Flutter applications, Firebase Authentication provides a robust and straightforward way to implement this feature. This article will guide you through integrating Firebase Authentication in your Flutter app to automatically send and manage email verification.

Prerequisites

  • A Flutter project set up and running.
  • A Firebase project configured for your Flutter application.
  • Firebase Authentication enabled (specifically Email/Password provider) in your Firebase console.

1. Setting Up Firebase in Your Flutter Project

First, ensure you have the necessary Firebase packages installed in your pubspec.yaml file:


dependencies:
  flutter:
    sdk: flutter
  firebase_core: ^latest_version
  firebase_auth: ^latest_version

After adding these, run flutter pub get. Then, initialize Firebase in your main.dart file, typically within the main function:


import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Firebase Email Verify',
      home: AuthWrapper(), // We'll create this later
    );
  }
}

2. User Registration and Sending Verification Email

The core idea is to send an email verification link immediately after a user successfully registers. Firebase Auth provides a dedicated method for this.

Here's an example of a registration function:


import 'package:firebase_auth/firebase_auth.dart';

Future<void> registerUserAndSendVerification(String email, String password) async {
  try {
    UserCredential userCredential = await FirebaseAuth.instance.createUserWithEmailAndPassword(
      email: email,
      password: password,
    );

    User? user = userCredential.user;
    if (user != null) {
      await user.sendEmailVerification();
      print('Verification email sent to ${user.email}');
      // You might want to show a SnackBar or AlertDialog to the user
      // indicating that an email has been sent.
    }
  } on FirebaseAuthException catch (e) {
    if (e.code == 'weak-password') {
      print('The password provided is too weak.');
    } else if (e.code == 'email-already-in-use') {
      print('The account already exists for that email.');
    } else {
      print('Error during registration: ${e.message}');
    }
  } catch (e) {
    print(e);
  }
}

After calling user.sendEmailVerification(), Firebase automatically sends an email to the registered address containing a link. When the user clicks this link, their email verification status is updated in Firebase.

3. Checking Email Verification Status

Once the user has registered and potentially clicked the verification link, your application needs a way to check their verification status. This is crucial for controlling access to certain features.

The key is to use currentUser?.emailVerified. However, it's important to know that after a user verifies their email (e.g., by clicking a link outside the app), the emailVerified property within your app's current User object won't automatically update. You need to explicitly reload the user's data:


import 'package:firebase_auth/firebase_auth.dart';

Future<bool> checkIfEmailIsVerified() async {
  User? user = FirebaseAuth.instance.currentUser;
  if (user != null) {
    // Reload the user to get the most up-to-date status
    await user.reload();
    user = FirebaseAuth.instance.currentUser; // Get the reloaded user object
    return user?.emailVerified ?? false;
  }
  return false;
}

You can use this function to determine what content to show the user. For instance, redirect them to a "verify your email" screen if not verified, or to the main app dashboard if they are.

4. Handling Authentication State Changes

For a dynamic user experience, you should listen to authentication state changes. This allows your app to react in real-time when a user logs in, logs out, or crucially, when their email verification status changes (after a reload). The authStateChanges() stream is perfect for this.


import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';

class AuthWrapper extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const CircularProgressIndicator(); // Or a splash screen
        }

        if (snapshot.hasData) {
          final user = snapshot.data!;
          // For simplicity, we assume the user object from authStateChanges
          // might not be reloaded immediately after external verification.
          // A dedicated screen will handle the reload and check.
          if (!user.emailVerified) {
            return EmailVerificationScreen();
          } else {
            return HomeScreen();
          }
        }
        return LoginScreen(); // Or RegistrationScreen
      },
    );
  }
}

// Example EmailVerificationScreen
class EmailVerificationScreen extends StatefulWidget {
  @override
  _EmailVerificationScreenState createState() => _EmailVerificationScreenState();
}

class _EmailVerificationScreenState extends State<EmailVerificationScreen> {
  User? _user;
  bool _isVerifying = false;

  @override
  void initState() {
    super.initState();
    _user = FirebaseAuth.instance.currentUser;
    // Periodically check or provide a button to check
    _checkEmailVerifiedPeriodically();
  }

  void _checkEmailVerifiedPeriodically() {
    // A simple timer to check verification status every few seconds.
    // In a real app, consider a "Refresh" button or more sophisticated polling.
    Future.delayed(Duration(seconds: 3), () async {
      if (!mounted) return;
      if (_user != null) {
        await _user!.reload(); // Get the latest user data from Firebase
        _user = FirebaseAuth.instance.currentUser; // Update the local user object
        if (_user!.emailVerified) {
          // If verified, navigate away (e.g., to home screen)
          Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (_) => HomeScreen()));
        } else {
          _checkEmailVerifiedPeriodically(); // Check again
        }
      }
    });
  }

  Future<void> _resendVerificationEmail() async {
    setState(() { _isVerifying = true; });
    try {
      await _user?.sendEmailVerification();
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Verification email sent! Please check your inbox.')),
      );
    } catch (e) {
      print('Error resending verification email: $e');
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Failed to resend email.')),
      );
    } finally {
      setState(() { _isVerifying = false; });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Verify Your Email')),
      body: Center(
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                'A verification email has been sent to ${_user?.email}. Please check your inbox and spam folder.',
                textAlign: TextAlign.center,
                style: TextStyle(fontSize: 16),
              ),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: _isVerifying ? null : _resendVerificationEmail,
                child: _isVerifying ? CircularProgressIndicator(color: Colors.white) : Text('Resend Email'),
              ),
              SizedBox(height: 10),
              TextButton(
                onPressed: () {
                  // Option to sign out if they can't verify
                  FirebaseAuth.instance.signOut();
                },
                child: Text('Sign Out'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

// Dummy screens for navigation example
class LoginScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(appBar: AppBar(title: Text('Login')), body: Center(child: Text('Login Page')));
  }
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Home')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Welcome, you are verified!', style: TextStyle(fontSize: 18)),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                FirebaseAuth.instance.signOut();
              },
              child: Text('Sign Out'),
            ),
          ],
        ),
      ),
    );
  }
}

The EmailVerificationScreen demonstrates a common pattern: informing the user, providing a "Resend Email" option, and periodically checking their verification status by calling user.reload().

Conclusion

Automating email verification with Flutter and Firebase Authentication is a straightforward yet powerful way to enhance the security and integrity of your application. By sending verification emails immediately upon registration and implementing robust checks for the emailVerified status, you ensure that your users have confirmed their email addresses, leading to a more reliable and trustworthy user base. Remember to guide your users clearly through the verification process and provide options for resending emails to improve their overall experience.

Related Articles

May 14, 2026

Building a Multi-Event Countdown Timer Widget with Reminders, Notifications, Repeat, and Custom Labels in Flutter

Building a Multi-Event Countdown Timer Widget with Reminders, Notifications, Repeat, and Custom Labels in Flutter Countdown timers are essential in many applic

May 11, 2026

Unleashing Dynamic UIs: Flutter's Animation Prowess

Unleashing Dynamic UIs: Flutter's Animation Prowess for Slide & Scale Effects Flutter's declarative UI framework, combined with its powerful animation capabilit

May 11, 2026

Building a Product Detail Page Widget in Flutter with Related Items, Review Carousel, Promo Badges, and Quick Buy

Building a Product Detail Page Widget in Flutter with Related Items, Review Carousel, Promo Badges, and Quick Buy A well-designed Product Detail Page (PDP) is