Firebase Auth (Dart/Flutter)

authentication-libraryFirebaseDartFlutterOAuthJWTmobilesecurity

Authentication Library

Firebase Auth (Dart/Flutter)

Overview

Firebase Auth for Flutter is Google's authentication SDK for Flutter applications from the Firebase platform. As of 2025, it serves as the core of the FlutterFire ecosystem, providing unified authentication experiences for iOS, Android, Web, and desktop applications. It supports a rich variety of authentication methods including email/password authentication, OAuth (Google, Facebook, Apple, etc.), anonymous authentication, and phone number authentication, providing enterprise-level user management capabilities through integration with Firebase Console.

Details

Firebase Auth for Flutter is the definitive cross-platform authentication solution. Key features include:

  • Multi-platform Support: Unified API across iOS, Android, Web, macOS, Windows, and Linux
  • Rich Authentication Methods: Email/password, OAuth, anonymous, phone number, and custom token authentication
  • Real-time State Management: authStateChanges, userChanges, and idTokenChanges streams
  • Security Features: Multi-factor authentication, email verification, and password reset functionality
  • Offline Support: Automatic authentication state persistence and offline capabilities
  • Firebase Integration: Complete integration with Firestore, Cloud Functions, Analytics, and more

Pros and Cons

Pros

  • High reliability with enterprise-grade authentication infrastructure provided by Google
  • Excellent code reusability through cross-platform support
  • Comprehensive user management and analytics via Firebase Console
  • Real-time authentication state management with reactive UI updates
  • Easy integration with rich OAuth providers
  • Automatic token management and refresh functionality

Cons

  • Vendor lock-in due to dependency on Firebase ecosystem
  • Constraints in implementing custom authentication logic
  • Firebase usage fees apply (free tier available)
  • Difficulty handling complex enterprise authentication requirements
  • Some features require Google account or internet connection

Reference Pages

Code Examples

Basic Setup and Installation

# Install Firebase CLI
npm install -g firebase-tools

# Login to Firebase
firebase login

# Configure Firebase in Flutter project
flutter pub add firebase_core
flutter pub add firebase_auth

# Configure with FlutterFire CLI
dart pub global activate flutterfire_cli
flutterfire configure

# Rebuild project
flutter run

Firebase Initialization and Email/Password Authentication

// main.dart - Firebase initialization
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'firebase_options.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  // Initialize Firebase
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  
  // Use emulator for development environment
  if (kDebugMode) {
    await FirebaseAuth.instance.useAuthEmulator('localhost', 9099);
  }
  
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Firebase Auth Demo',
      home: AuthWrapper(),
    );
  }
}

// auth_wrapper.dart - Screen switching based on authentication state
class AuthWrapper extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: FirebaseAuth.instance.authStateChanges(),
      builder: (context, snapshot) {
        // Check authentication state
        if (snapshot.connectionState == ConnectionState.waiting) {
          return Scaffold(
            body: Center(child: CircularProgressIndicator()),
          );
        } else if (snapshot.hasData && snapshot.data != null) {
          // Logged in
          return HomePage();
        } else {
          // Not logged in
          return LoginPage();
        }
      },
    );
  }
}

// login_page.dart - Login page
class LoginPage extends StatefulWidget {
  @override
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();
  final _formKey = GlobalKey<FormState>();
  bool _isLoading = false;

  // User registration with email and password
  Future<void> _registerWithEmailPassword() async {
    if (!_formKey.currentState!.validate()) return;

    setState(() => _isLoading = true);

    try {
      final credential = await FirebaseAuth.instance
          .createUserWithEmailAndPassword(
        email: _emailController.text.trim(),
        password: _passwordController.text,
      );

      // Send email verification after registration
      await credential.user?.sendEmailVerification();
      
      _showMessage('Registration successful! Please check your verification email.');
    } on FirebaseAuthException catch (e) {
      String message;
      switch (e.code) {
        case 'weak-password':
          message = 'The password is too weak.';
          break;
        case 'email-already-in-use':
          message = 'This email address is already in use.';
          break;
        case 'invalid-email':
          message = 'Invalid email address.';
          break;
        default:
          message = 'Registration failed: ${e.message}';
      }
      _showMessage(message);
    } catch (e) {
      _showMessage('Unexpected error occurred: $e');
    } finally {
      setState(() => _isLoading = false);
    }
  }

  // Sign in with email and password
  Future<void> _signInWithEmailPassword() async {
    if (!_formKey.currentState!.validate()) return;

    setState(() => _isLoading = true);

    try {
      await FirebaseAuth.instance.signInWithEmailAndPassword(
        email: _emailController.text.trim(),
        password: _passwordController.text,
      );
    } on FirebaseAuthException catch (e) {
      String message;
      switch (e.code) {
        case 'user-not-found':
          message = 'User not found.';
          break;
        case 'wrong-password':
          message = 'Incorrect password.';
          break;
        case 'invalid-email':
          message = 'Invalid email address.';
          break;
        case 'user-disabled':
          message = 'This account has been disabled.';
          break;
        default:
          message = 'Login failed: ${e.message}';
      }
      _showMessage(message);
    } finally {
      setState(() => _isLoading = false);
    }
  }

  void _showMessage(String message) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text(message)),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Login')),
      body: Padding(
        padding: EdgeInsets.all(16.0),
        child: Form(
          key: _formKey,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              TextFormField(
                controller: _emailController,
                decoration: InputDecoration(
                  labelText: 'Email Address',
                  border: OutlineInputBorder(),
                ),
                keyboardType: TextInputType.emailAddress,
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Please enter email address';
                  }
                  if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$')
                      .hasMatch(value)) {
                    return 'Please enter a valid email address';
                  }
                  return null;
                },
              ),
              SizedBox(height: 16),
              TextFormField(
                controller: _passwordController,
                decoration: InputDecoration(
                  labelText: 'Password',
                  border: OutlineInputBorder(),
                ),
                obscureText: true,
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Please enter password';
                  }
                  if (value.length < 6) {
                    return 'Password must be at least 6 characters';
                  }
                  return null;
                },
              ),
              SizedBox(height: 24),
              if (_isLoading)
                CircularProgressIndicator()
              else ...[
                ElevatedButton(
                  onPressed: _signInWithEmailPassword,
                  style: ElevatedButton.styleFrom(
                    minimumSize: Size(double.infinity, 50),
                  ),
                  child: Text('Sign In'),
                ),
                SizedBox(height: 16),
                TextButton(
                  onPressed: _registerWithEmailPassword,
                  child: Text('Register'),
                ),
                TextButton(
                  onPressed: _resetPassword,
                  child: Text('Forgot Password'),
                ),
              ],
            ],
          ),
        ),
      ),
    );
  }

  // Password reset
  Future<void> _resetPassword() async {
    final email = _emailController.text.trim();
    if (email.isEmpty) {
      _showMessage('Please enter email address');
      return;
    }

    try {
      await FirebaseAuth.instance.sendPasswordResetEmail(email: email);
      _showMessage('Password reset email sent');
    } on FirebaseAuthException catch (e) {
      _showMessage('Error: ${e.message}');
    }
  }

  @override
  void dispose() {
    _emailController.dispose();
    _passwordController.dispose();
    super.dispose();
  }
}

OAuth Authentication (Google, Apple, etc.) Implementation

// oauth_service.dart - OAuth authentication service
import 'package:google_sign_in/google_sign_in.dart';
import 'package:flutter_facebook_auth/flutter_facebook_auth.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/foundation.dart';

class OAuthService {
  // Google Sign In
  static Future<UserCredential?> signInWithGoogle() async {
    try {
      if (kIsWeb) {
        // Web Google authentication
        GoogleAuthProvider googleProvider = GoogleAuthProvider();
        googleProvider.addScope('https://www.googleapis.com/auth/contacts.readonly');
        googleProvider.setCustomParameters({
          'login_hint': '[email protected]'
        });

        return await FirebaseAuth.instance.signInWithPopup(googleProvider);
      } else {
        // Native Google authentication
        final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn();
        if (googleUser == null) return null;

        final GoogleSignInAuthentication googleAuth = 
            await googleUser.authentication;

        final credential = GoogleAuthProvider.credential(
          accessToken: googleAuth.accessToken,
          idToken: googleAuth.idToken,
        );

        return await FirebaseAuth.instance.signInWithCredential(credential);
      }
    } catch (e) {
      print('Google sign-in error: $e');
      return null;
    }
  }

  // Facebook Sign In
  static Future<UserCredential?> signInWithFacebook() async {
    try {
      if (kIsWeb) {
        // Web Facebook authentication
        FacebookAuthProvider facebookProvider = FacebookAuthProvider();
        facebookProvider.addScope('email');
        facebookProvider.setCustomParameters({'display': 'popup'});

        return await FirebaseAuth.instance.signInWithPopup(facebookProvider);
      } else {
        // Native Facebook authentication
        final LoginResult loginResult = await FacebookAuth.instance.login();
        
        if (loginResult.status != LoginStatus.success) return null;

        final OAuthCredential facebookAuthCredential = 
            FacebookAuthProvider.credential(loginResult.accessToken!.token);

        return await FirebaseAuth.instance
            .signInWithCredential(facebookAuthCredential);
      }
    } catch (e) {
      print('Facebook sign-in error: $e');
      return null;
    }
  }

  // Apple Sign In
  static Future<UserCredential?> signInWithApple() async {
    try {
      final appleProvider = AppleAuthProvider();
      appleProvider.addScope('email');
      appleProvider.addScope('name');

      if (kIsWeb) {
        return await FirebaseAuth.instance.signInWithPopup(appleProvider);
      } else {
        return await FirebaseAuth.instance.signInWithProvider(appleProvider);
      }
    } catch (e) {
      print('Apple sign-in error: $e');
      return null;
    }
  }

  // Anonymous Sign In
  static Future<UserCredential?> signInAnonymously() async {
    try {
      return await FirebaseAuth.instance.signInAnonymously();
    } on FirebaseAuthException catch (e) {
      switch (e.code) {
        case "operation-not-allowed":
          print("Anonymous authentication is not enabled");
          break;
        default:
          print("Anonymous authentication error: ${e.message}");
      }
      return null;
    }
  }

  // Sign Out
  static Future<void> signOut() async {
    await GoogleSignIn().signOut();
    await FacebookAuth.instance.logOut();
    await FirebaseAuth.instance.signOut();
  }
}

// oauth_buttons.dart - OAuth authentication button widget
class OAuthButtons extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        // Google Sign In Button
        ElevatedButton.icon(
          onPressed: () async {
            final result = await OAuthService.signInWithGoogle();
            if (result != null) {
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text('Signed in with Google')),
              );
            }
          },
          icon: Icon(Icons.login),
          label: Text('Sign in with Google'),
          style: ElevatedButton.styleFrom(
            backgroundColor: Colors.red,
            foregroundColor: Colors.white,
            minimumSize: Size(double.infinity, 50),
          ),
        ),
        SizedBox(height: 12),
        
        // Facebook Sign In Button
        ElevatedButton.icon(
          onPressed: () async {
            final result = await OAuthService.signInWithFacebook();
            if (result != null) {
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text('Signed in with Facebook')),
              );
            }
          },
          icon: Icon(Icons.facebook),
          label: Text('Sign in with Facebook'),
          style: ElevatedButton.styleFrom(
            backgroundColor: Colors.blue[800],
            foregroundColor: Colors.white,
            minimumSize: Size(double.infinity, 50),
          ),
        ),
        SizedBox(height: 12),
        
        // Apple Sign In Button (iOS/Web)
        if (Theme.of(context).platform == TargetPlatform.iOS || kIsWeb)
          ElevatedButton.icon(
            onPressed: () async {
              final result = await OAuthService.signInWithApple();
              if (result != null) {
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(content: Text('Signed in with Apple')),
                );
              }
            },
            icon: Icon(Icons.apple),
            label: Text('Sign in with Apple'),
            style: ElevatedButton.styleFrom(
              backgroundColor: Colors.black,
              foregroundColor: Colors.white,
              minimumSize: Size(double.infinity, 50),
            ),
          ),
        
        SizedBox(height: 12),
        
        // Anonymous Sign In Button
        TextButton.icon(
          onPressed: () async {
            final result = await OAuthService.signInAnonymously();
            if (result != null) {
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text('Signed in anonymously')),
              );
            }
          },
          icon: Icon(Icons.person_outline),
          label: Text('Sign in Anonymously'),
        ),
      ],
    );
  }
}

User Information Management and Profile Updates

// user_profile_page.dart - User profile management
class UserProfilePage extends StatefulWidget {
  @override
  _UserProfilePageState createState() => _UserProfilePageState();
}

class _UserProfilePageState extends State<UserProfilePage> {
  final _displayNameController = TextEditingController();
  final _currentPasswordController = TextEditingController();
  final _newPasswordController = TextEditingController();
  bool _isLoading = false;

  @override
  void initState() {
    super.initState();
    _loadUserData();
  }

  void _loadUserData() {
    final user = FirebaseAuth.instance.currentUser;
    if (user != null) {
      _displayNameController.text = user.displayName ?? '';
    }
  }

  // Update profile
  Future<void> _updateProfile() async {
    final user = FirebaseAuth.instance.currentUser;
    if (user == null) return;

    setState(() => _isLoading = true);

    try {
      await user.updateDisplayName(_displayNameController.text);
      await user.reload();
      
      _showMessage('Profile updated successfully');
    } catch (e) {
      _showMessage('Update failed: $e');
    } finally {
      setState(() => _isLoading = false);
    }
  }

  // Change password
  Future<void> _changePassword() async {
    final user = FirebaseAuth.instance.currentUser;
    if (user == null) return;

    if (_currentPasswordController.text.isEmpty || 
        _newPasswordController.text.isEmpty) {
      _showMessage('Please enter current password and new password');
      return;
    }

    setState(() => _isLoading = true);

    try {
      // Re-authenticate
      final credential = EmailAuthProvider.credential(
        email: user.email!,
        password: _currentPasswordController.text,
      );
      await user.reauthenticateWithCredential(credential);

      // Update password
      await user.updatePassword(_newPasswordController.text);
      
      _currentPasswordController.clear();
      _newPasswordController.clear();
      _showMessage('Password changed successfully');
    } on FirebaseAuthException catch (e) {
      String message;
      switch (e.code) {
        case 'wrong-password':
          message = 'Current password is incorrect';
          break;
        case 'weak-password':
          message = 'New password is too weak';
          break;
        default:
          message = 'Password change failed: ${e.message}';
      }
      _showMessage(message);
    } finally {
      setState(() => _isLoading = false);
    }
  }

  // Send email verification
  Future<void> _sendEmailVerification() async {
    final user = FirebaseAuth.instance.currentUser;
    if (user == null) return;

    try {
      await user.sendEmailVerification();
      _showMessage('Verification email sent');
    } catch (e) {
      _showMessage('Send failed: $e');
    }
  }

  // Delete account
  Future<void> _deleteAccount() async {
    final confirmed = await _showConfirmDialog(
      'Delete Account',
      'Deleting your account will permanently remove all your data.\nAre you sure you want to continue?',
    );
    
    if (!confirmed) return;

    final user = FirebaseAuth.instance.currentUser;
    if (user == null) return;

    try {
      await user.delete();
      _showMessage('Account deleted successfully');
    } on FirebaseAuthException catch (e) {
      if (e.code == 'requires-recent-login') {
        _showMessage('For security, please re-login and try again');
      } else {
        _showMessage('Delete failed: ${e.message}');
      }
    }
  }

  Future<bool> _showConfirmDialog(String title, String message) async {
    return await showDialog<bool>(
      context: context,
      builder: (context) => AlertDialog(
        title: Text(title),
        content: Text(message),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(false),
            child: Text('Cancel'),
          ),
          TextButton(
            onPressed: () => Navigator.of(context).pop(true),
            child: Text('Delete'),
            style: TextButton.styleFrom(foregroundColor: Colors.red),
          ),
        ],
      ),
    ) ?? false;
  }

  void _showMessage(String message) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text(message)),
    );
  }

  @override
  Widget build(BuildContext context) {
    final user = FirebaseAuth.instance.currentUser;
    
    return Scaffold(
      appBar: AppBar(
        title: Text('Profile'),
        actions: [
          IconButton(
            onPressed: () async {
              await OAuthService.signOut();
            },
            icon: Icon(Icons.logout),
          ),
        ],
      ),
      body: user == null
          ? Center(child: Text('User not found'))
          : SingleChildScrollView(
              padding: EdgeInsets.all(16.0),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  // User information display
                  Card(
                    child: Padding(
                      padding: EdgeInsets.all(16.0),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text('Basic Information', style: Theme.of(context).textTheme.headlineSmall),
                          SizedBox(height: 16),
                          
                          if (user.photoURL != null)
                            CircleAvatar(
                              radius: 40,
                              backgroundImage: NetworkImage(user.photoURL!),
                            ),
                          
                          SizedBox(height: 16),
                          Text('Email: ${user.email ?? "Not set"}'),
                          SizedBox(height: 8),
                          Text('UID: ${user.uid}'),
                          SizedBox(height: 8),
                          Row(
                            children: [
                              Text('Email Verified: '),
                              Icon(
                                user.emailVerified ? Icons.check_circle : Icons.cancel,
                                color: user.emailVerified ? Colors.green : Colors.red,
                              ),
                              if (!user.emailVerified) ...[
                                SizedBox(width: 8),
                                TextButton(
                                  onPressed: _sendEmailVerification,
                                  child: Text('Send Verification Email'),
                                ),
                              ],
                            ],
                          ),
                          
                          SizedBox(height: 16),
                          TextField(
                            controller: _displayNameController,
                            decoration: InputDecoration(
                              labelText: 'Display Name',
                              border: OutlineInputBorder(),
                            ),
                          ),
                          
                          SizedBox(height: 16),
                          ElevatedButton(
                            onPressed: _isLoading ? null : _updateProfile,
                            child: _isLoading
                                ? CircularProgressIndicator()
                                : Text('Update Profile'),
                          ),
                        ],
                      ),
                    ),
                  ),
                  
                  SizedBox(height: 16),
                  
                  // Password change section
                  if (user.providerData.any((info) => info.providerId == 'password'))
                    Card(
                      child: Padding(
                        padding: EdgeInsets.all(16.0),
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Text('Change Password', 
                                style: Theme.of(context).textTheme.headlineSmall),
                            SizedBox(height: 16),
                            
                            TextField(
                              controller: _currentPasswordController,
                              decoration: InputDecoration(
                                labelText: 'Current Password',
                                border: OutlineInputBorder(),
                              ),
                              obscureText: true,
                            ),
                            
                            SizedBox(height: 16),
                            
                            TextField(
                              controller: _newPasswordController,
                              decoration: InputDecoration(
                                labelText: 'New Password',
                                border: OutlineInputBorder(),
                              ),
                              obscureText: true,
                            ),
                            
                            SizedBox(height: 16),
                            
                            ElevatedButton(
                              onPressed: _isLoading ? null : _changePassword,
                              child: Text('Change Password'),
                            ),
                          ],
                        ),
                      ),
                    ),
                  
                  SizedBox(height: 16),
                  
                  // Account deletion section
                  Card(
                    child: Padding(
                      padding: EdgeInsets.all(16.0),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          Text('Dangerous Actions', 
                              style: Theme.of(context).textTheme.headlineSmall),
                          SizedBox(height: 16),
                          
                          ElevatedButton(
                            onPressed: _deleteAccount,
                            style: ElevatedButton.styleFrom(
                              backgroundColor: Colors.red,
                              foregroundColor: Colors.white,
                            ),
                            child: Text('Delete Account'),
                          ),
                        ],
                      ),
                    ),
                  ),
                ],
              ),
            ),
    );
  }

  @override
  void dispose() {
    _displayNameController.dispose();
    _currentPasswordController.dispose();
    _newPasswordController.dispose();
    super.dispose();
  }
}

Authentication State Management and Advanced Features

// auth_state_service.dart - Authentication state management service
class AuthStateService {
  static final FirebaseAuth _auth = FirebaseAuth.instance;

  // Get current user
  static User? get currentUser => _auth.currentUser;

  // Authentication state change stream
  static Stream<User?> get authStateChanges => _auth.authStateChanges();

  // User change stream (includes profile changes)
  static Stream<User?> get userChanges => _auth.userChanges();

  // ID token change stream
  static Stream<User?> get idTokenChanges => _auth.idTokenChanges();

  // Set persistence (Web only)
  static Future<void> setPersistence(Persistence persistence) async {
    if (kIsWeb) {
      await _auth.setPersistence(persistence);
    }
  }

  // Get current user details
  static Future<User?> reloadCurrentUser() async {
    final user = _auth.currentUser;
    if (user != null) {
      await user.reload();
      return _auth.currentUser;
    }
    return null;
  }

  // Get ID token
  static Future<String?> getIdToken({bool forceRefresh = false}) async {
    final user = _auth.currentUser;
    if (user != null) {
      return await user.getIdToken(forceRefresh);
    }
    return null;
  }

  // Get custom claims
  static Future<Map<String, dynamic>?> getCustomClaims() async {
    final user = _auth.currentUser;
    if (user != null) {
      final idTokenResult = await user.getIdTokenResult();
      return idTokenResult.claims;
    }
    return null;
  }
}

// auth_guard.dart - Authentication guard widget
class AuthGuard extends StatelessWidget {
  final Widget child;
  final Widget? loginPage;
  final bool requireEmailVerification;

  const AuthGuard({
    Key? key,
    required this.child,
    this.loginPage,
    this.requireEmailVerification = false,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<User?>(
      stream: AuthStateService.authStateChanges,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return Scaffold(
            body: Center(child: CircularProgressIndicator()),
          );
        }

        final user = snapshot.data;
        
        // User does not exist
        if (user == null) {
          return loginPage ?? LoginPage();
        }

        // Email verification required
        if (requireEmailVerification && !user.emailVerified) {
          return EmailVerificationPage();
        }

        // Authenticated user
        return child;
      },
    );
  }
}

// email_verification_page.dart - Email verification confirmation page
class EmailVerificationPage extends StatefulWidget {
  @override
  _EmailVerificationPageState createState() => _EmailVerificationPageState();
}

class _EmailVerificationPageState extends State<EmailVerificationPage> {
  bool _isLoading = false;
  Timer? _timer;

  @override
  void initState() {
    super.initState();
    _checkEmailVerification();
  }

  void _checkEmailVerification() {
    _timer = Timer.periodic(Duration(seconds: 3), (timer) async {
      await FirebaseAuth.instance.currentUser?.reload();
      final user = FirebaseAuth.instance.currentUser;
      
      if (user?.emailVerified == true) {
        timer.cancel();
        // Update page after verification confirmation
        if (mounted) {
          setState(() {});
        }
      }
    });
  }

  Future<void> _resendVerificationEmail() async {
    setState(() => _isLoading = true);

    try {
      await FirebaseAuth.instance.currentUser?.sendEmailVerification();
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Verification email resent')),
      );
    } catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Send failed: $e')),
      );
    } finally {
      setState(() => _isLoading = false);
    }
  }

  @override
  Widget build(BuildContext context) {
    final user = FirebaseAuth.instance.currentUser;

    return Scaffold(
      appBar: AppBar(
        title: Text('Email Verification'),
        actions: [
          IconButton(
            onPressed: () => FirebaseAuth.instance.signOut(),
            icon: Icon(Icons.logout),
          ),
        ],
      ),
      body: Padding(
        padding: EdgeInsets.all(16.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Icon(
              Icons.mark_email_unread,
              size: 100,
              color: Colors.orange,
            ),
            SizedBox(height: 24),
            
            Text(
              'Email Verification Required',
              style: Theme.of(context).textTheme.headlineSmall,
              textAlign: TextAlign.center,
            ),
            
            SizedBox(height: 16),
            
            Text(
              'Please click the verification link sent to ${user?.email}.',
              style: Theme.of(context).textTheme.bodyLarge,
              textAlign: TextAlign.center,
            ),
            
            SizedBox(height: 32),
            
            ElevatedButton(
              onPressed: _isLoading ? null : _resendVerificationEmail,
              child: _isLoading
                  ? CircularProgressIndicator()
                  : Text('Resend Verification Email'),
            ),
            
            SizedBox(height: 16),
            
            TextButton(
              onPressed: () async {
                await FirebaseAuth.instance.currentUser?.reload();
                setState(() {});
              },
              child: Text('Check Verification Status'),
            ),
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    _timer?.cancel();
    super.dispose();
  }
}