Firebase Authentication in Flutter
Firebase Authentication provides a complete authentication system for your Flutter applications. This guide will show you how to implement various authentication methods using Firebase.
Why Use Firebase Authentication?
Firebase Authentication offers several benefits:
- Multiple sign-in methods
- Secure authentication
- Easy integration
- User management
- Cross-platform support
- Real-time updates
- Cost-effective
Implementation Steps
-
Setup Dependencies
# pubspec.yaml dependencies: firebase_core: ^2.24.2 firebase_auth: ^4.15.3 google_sign_in: ^6.1.6 flutter_facebook_auth: ^6.0.3 sign_in_with_apple: ^5.0.0
-
Configure Firebase
Android (android/app/src/main/AndroidManifest.xml):
<manifest> <uses-permission android:name="android.permission.INTERNET"/> </manifest>
iOS (ios/Runner/Info.plist):
<key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <string>fb[YOUR_FACEBOOK_APP_ID]</string> </array> </dict> </array>
-
Create Authentication Service
class AuthService { final FirebaseAuth _auth = FirebaseAuth.instance; final GoogleSignIn _googleSignIn = GoogleSignIn(); final FacebookAuth _facebookAuth = FacebookAuth.instance; // Email & Password Authentication Future<UserCredential?> signInWithEmailAndPassword( String email, String password, ) async { try { return await _auth.signInWithEmailAndPassword( email: email, password: password, ); } catch (e) { print('Error signing in: $e'); return null; } } Future<UserCredential?> createUserWithEmailAndPassword( String email, String password, ) async { try { return await _auth.createUserWithEmailAndPassword( email: email, password: password, ); } catch (e) { print('Error creating user: $e'); return null; } } // Google Sign-In Future<UserCredential?> signInWithGoogle() async { try { 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 _auth.signInWithCredential(credential); } catch (e) { print('Error signing in with Google: $e'); return null; } } // Facebook Sign-In Future<UserCredential?> signInWithFacebook() async { try { final LoginResult result = await _facebookAuth.login(); if (result.status != LoginStatus.success) return null; final AccessToken accessToken = result.accessToken!; final OAuthCredential credential = FacebookAuthProvider.credential(accessToken.token); return await _auth.signInWithCredential(credential); } catch (e) { print('Error signing in with Facebook: $e'); return null; } } // Apple Sign-In Future<UserCredential?> signInWithApple() async { try { final appleCredential = await SignInWithApple.getAppleIDCredential( scopes: [ AppleIDAuthorizationScopes.email, AppleIDAuthorizationScopes.fullName, ], ); final oauthCredential = OAuthProvider('apple.com').credential( idToken: appleCredential.identityToken, accessToken: appleCredential.authorizationCode, ); return await _auth.signInWithCredential(oauthCredential); } catch (e) { print('Error signing in with Apple: $e'); return null; } } // Sign Out Future<void> signOut() async { await Future.wait([ _auth.signOut(), _googleSignIn.signOut(), _facebookAuth.logOut(), ]); } // Get Current User User? get currentUser => _auth.currentUser; // Stream of Auth State Changes Stream<User?> get authStateChanges => _auth.authStateChanges(); }
-
Create Authentication Manager
class AuthManager { final AuthService _authService = AuthService(); Future<User?> signInWithEmailAndPassword( String email, String password, ) async { final credential = await _authService.signInWithEmailAndPassword( email, password, ); return credential?.user; } Future<User?> createUserWithEmailAndPassword( String email, String password, ) async { final credential = await _authService.createUserWithEmailAndPassword( email, password, ); return credential?.user; } Future<User?> signInWithGoogle() async { final credential = await _authService.signInWithGoogle(); return credential?.user; } Future<User?> signInWithFacebook() async { final credential = await _authService.signInWithFacebook(); return credential?.user; } Future<User?> signInWithApple() async { final credential = await _authService.signInWithApple(); return credential?.user; } Future<void> signOut() async { await _authService.signOut(); } User? get currentUser => _authService.currentUser; Stream<User?> get authStateChanges => _authService.authStateChanges; }
-
Create Authentication UI
class AuthScreen extends StatefulWidget { @override _AuthScreenState createState() => _AuthScreenState(); } class _AuthScreenState extends State<AuthScreen> { final AuthManager _authManager = AuthManager(); final _formKey = GlobalKey<FormState>(); final _emailController = TextEditingController(); final _passwordController = TextEditingController(); bool _isLoading = false; bool _isSignUp = false; Future<void> _handleEmailPasswordAuth() async { if (!_formKey.currentState!.validate()) return; setState(() { _isLoading = true; }); try { final user = _isSignUp ? await _authManager.createUserWithEmailAndPassword( _emailController.text, _passwordController.text, ) : await _authManager.signInWithEmailAndPassword( _emailController.text, _passwordController.text, ); if (user != null) { Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => HomeScreen()), ); } } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(e.toString())), ); } finally { setState(() { _isLoading = false; }); } } Future<void> _handleGoogleSignIn() async { setState(() { _isLoading = true; }); try { final user = await _authManager.signInWithGoogle(); if (user != null) { Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => HomeScreen()), ); } } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(e.toString())), ); } finally { setState(() { _isLoading = false; }); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(_isSignUp ? 'Sign Up' : 'Sign In'), ), body: SingleChildScrollView( padding: EdgeInsets.all(16), child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ TextFormField( controller: _emailController, decoration: InputDecoration( labelText: 'Email', border: OutlineInputBorder(), ), validator: (value) { if (value == null || value.isEmpty) { return 'Please enter your email'; } 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 your password'; } return null; }, ), SizedBox(height: 16), ElevatedButton( onPressed: _isLoading ? null : _handleEmailPasswordAuth, child: _isLoading ? CircularProgressIndicator() : Text(_isSignUp ? 'Sign Up' : 'Sign In'), ), SizedBox(height: 16), TextButton( onPressed: () { setState(() { _isSignUp = !_isSignUp; }); }, child: Text(_isSignUp ? 'Already have an account? Sign In' : 'Don\'t have an account? Sign Up'), ), SizedBox(height: 16), Divider(), SizedBox(height: 16), ElevatedButton.icon( onPressed: _isLoading ? null : _handleGoogleSignIn, icon: Icon(Icons.g_mobiledata), label: Text('Sign in with Google'), ), ], ), ), ), ); } }
Advanced Features
-
Password Reset
class PasswordResetService { final FirebaseAuth _auth = FirebaseAuth.instance; Future<void> sendPasswordResetEmail(String email) async { try { await _auth.sendPasswordResetEmail(email: email); } catch (e) { print('Error sending password reset email: $e'); rethrow; } } }
-
Email Verification
class EmailVerificationService { final FirebaseAuth _auth = FirebaseAuth.instance; Future<void> sendEmailVerification() async { try { await _auth.currentUser?.sendEmailVerification(); } catch (e) { print('Error sending email verification: $e'); rethrow; } } Future<void> reloadUser() async { try { await _auth.currentUser?.reload(); } catch (e) { print('Error reloading user: $e'); rethrow; } } }
-
Phone Authentication
class PhoneAuthService { final FirebaseAuth _auth = FirebaseAuth.instance; Future<void> verifyPhoneNumber({ required String phoneNumber, required Function(PhoneAuthCredential) onVerificationCompleted, required Function(FirebaseAuthException) onVerificationFailed, required Function(String, int?) onCodeSent, required Function(String) onCodeAutoRetrievalTimeout, }) async { await _auth.verifyPhoneNumber( phoneNumber: phoneNumber, verificationCompleted: onVerificationCompleted, verificationFailed: onVerificationFailed, codeSent: onCodeSent, codeAutoRetrievalTimeout: onCodeAutoRetrievalTimeout, ); } Future<UserCredential> signInWithCredential( PhoneAuthCredential credential, ) async { return await _auth.signInWithCredential(credential); } }
Best Practices
-
Security
- Implement proper validation
- Handle sensitive data
- Use secure storage
- Implement proper error handling
-
User Experience
- Provide clear feedback
- Handle edge cases
- Implement proper loading states
- Maintain session state
-
Error Handling
- Handle network errors
- Validate user input
- Provide meaningful error messages
- Implement retry mechanisms
Common Use Cases
-
User Management
- User registration
- User login
- Password reset
- Email verification
-
Social Authentication
- Google Sign-In
- Facebook Login
- Apple Sign-In
- Twitter Authentication
-
Security Features
- Session management
- Token refresh
- Account linking
- Multi-factor authentication
Conclusion
Implementing Firebase Authentication in your Flutter application provides a secure and reliable way to handle user authentication. By following these guidelines and implementing the provided examples, you can create a robust authentication system that supports multiple sign-in methods and ensures the security of your users’ data.