Flutter App Auth Manager π
A comprehensive Flutter authentication manager package that provides a unified interface for various authentication methods including Firebase Auth, Google Sign-In, Apple Sign-In, and more.
Features β¨
Core Authentication
- Email/Password Authentication - Traditional sign-up and sign-in
- Anonymous Authentication - Guest access functionality
- Social Authentication - Google, Apple, Facebook, Twitter, Microsoft, GitHub
- Phone Authentication - SMS-based verification
- Biometric Authentication - Fingerprint and Face ID support
Advanced Features
- Multi-Factor Authentication (MFA) - Enhanced security
- Account Linking/Unlinking - Connect multiple providers
- Session Management - Token refresh and validation
- Password Management - Reset, update, strength validation
- Email Verification - Verify user email addresses
- Profile Management - Update user information
- Custom Claims - Role-based access control
- Offline Support - Cached authentication state
Developer Experience
- Type-Safe Models - Using flutter_shared_utilities BaseDataModel
- Comprehensive Error Handling - Detailed error models with user-friendly messages
- Stream-Based State Management - Real-time authentication state updates
- Dependency Injection Ready - Abstract interface for easy testing and mocking
- Mixin-Based Architecture - Modular authentication utilities and validations
- Analytics & Monitoring - Built-in authentication analytics with app_logger_manager
- Debug Support - Comprehensive logging and debugging tools
- Clean Architecture - Separation of concerns with interfaces and implementations
Installation π¦
Add this package to your pubspec.yaml
:
dependencies:
app_auth_manager: ^1.0.1
# Required for Firebase Authentication
firebase_core: ^3.14.0
firebase_auth: ^5.6.0
# Required for Social Authentication
google_sign_in: ^6.3.0
sign_in_with_apple: ^7.0.1
# Required for Biometric Authentication (optional)
local_auth: ^2.3.0
# Required for Logging (optional but recommended)
app_logger_manager: ^1.0.2
Quick Start π
1. Initialize Firebase
Follow the Firebase setup guide to add Firebase to your Flutter app.
2. Configure Authentication Providers
Google Sign-In Setup
Android Configuration:
- Add your SHA-1 fingerprint to Firebase Console
- Download and add
google-services.json
toandroid/app/
- Update
android/build.gradle
:
buildscript {
dependencies {
classpath 'com.google.gms:google-services:4.3.15'
}
}
- Update
android/app/build.gradle
:
apply plugin: 'com.google.gms.google-services'
android {
compileSdkVersion 34
defaultConfig {
minSdkVersion 21
targetSdkVersion 34
}
}
iOS Configuration:
- Download and add
GoogleService-Info.plist
toios/Runner/
- Update
ios/Runner/Info.plist
:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>REVERSED_CLIENT_ID</string>
<key>CFBundleURLSchemes</key>
<array>
<string>YOUR_REVERSED_CLIENT_ID</string>
</array>
</dict>
</array>
Apple Sign-In Setup
iOS Configuration:
- Enable Sign in with Apple in Apple Developer Console
- Add capability in Xcode:
Signing & Capabilities
β+ Capability
βSign in with Apple
- Update
ios/Runner/Info.plist
:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>apple-sign-in</string>
<key>CFBundleURLSchemes</key>
<array>
<string>your.bundle.identifier</string>
</array>
</dict>
</array>
3. Basic Usage
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:app_auth_manager/app_auth_manager.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
IAuthManager? _authManager;
bool _isInitializing = true;
@override
void initState() {
super.initState();
_initializeAuth();
}
Future<void> _initializeAuth() async {
_authManager = await FirebaseAuthManager.create();
if (mounted) {
setState(() {
_isInitializing = false;
});
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: _isInitializing || _authManager == null
? const Scaffold(
body: Center(child: CircularProgressIndicator()),
)
: StreamBuilder<AuthStateModel>(
stream: _authManager!.authStateStream,
builder: (context, snapshot) {
final authState = snapshot.data ?? AuthStateModel.initial();
if (authState.isLoading) {
return const Scaffold(
body: Center(child: CircularProgressIndicator()),
);
}
if (authState.isAuthenticated) {
return HomePage(authManager: _authManager!);
}
return LoginPage(authManager: _authManager!);
},
),
);
}
}
Authentication Methods π
Email/Password Authentication
// Sign up
final result = await authManager.signUpWithEmailAndPassword(
email: 'user@example.com',
password: 'securePassword123',
displayName: 'John Doe',
);
// Sign in
final result = await authManager.signInWithEmailAndPassword(
email: 'user@example.com',
password: 'securePassword123',
rememberMe: true,
);
// Handle result
if (result.success) {
print('Welcome ${result.user?.displayName}!');
} else {
print('Error: ${result.error}');
}
Social Authentication
// Google Sign-In
final googleResult = await authManager.signInWithGoogle();
// Apple Sign-In
final appleResult = await authManager.signInWithApple();
// Anonymous Sign-In
final anonymousResult = await authManager.signInAnonymously();
Password Management
// Send password reset email
await authManager.sendPasswordResetEmail(
email: 'user@example.com',
);
// Update password
await authManager.updatePassword(
currentPassword: 'oldPassword',
newPassword: 'newSecurePassword123',
);
// Validate password strength
bool isStrong = authManager.validatePasswordStrength('myPassword');
int score = authManager.getPasswordStrengthScore('myPassword'); // 0-4
Profile Management
// Update user profile
await authManager.updateProfile(
displayName: 'New Name',
photoURL: 'https://example.com/photo.jpg',
);
// Update email
await authManager.updateEmail(
newEmail: 'new@example.com',
password: 'currentPassword',
);
Account Linking
// Link Google account
await authManager.linkWithGoogle();
// Link Apple account
await authManager.linkWithApple();
// Unlink provider
await authManager.unlinkFromProvider(providerId: 'google.com');
// Get linked providers
List<String> providers = authManager.getLinkedProviders();
State Management π
The authentication manager provides real-time state updates through streams:
StreamBuilder<AuthStateModel>(
stream: authManager.authStateStream,
builder: (context, snapshot) {
final state = snapshot.data ?? AuthStateModel.initial();
return switch (state.status) {
AuthStatus.authenticated => AuthenticatedView(user: state.user!),
AuthStatus.unauthenticated => LoginView(),
AuthStatus.unknown => LoadingView(),
};
},
);
Authentication State Properties
final authState = authManager.currentState;
// Check authentication status
bool isAuthenticated = authState.isAuthenticated;
bool isLoading = authState.isLoading;
bool hasError = authState.hasError;
// Get current user
AuthUserModel? user = authState.user;
// Access user properties
if (user != null) {
print('User ID: ${user.uid}');
print('Email: ${user.email}');
print('Display Name: ${user.displayName}');
print('Email Verified: ${user.isEmailVerified}');
print('Providers: ${user.allProviderIds}');
}
Error Handling π¨
The package provides comprehensive error handling with user-friendly messages:
final result = await authManager.signInWithEmailAndPassword(
email: email,
password: password,
);
if (result.isFailure) {
final error = result.error;
final userMessage = authManager.getUserFriendlyErrorMessage(result.errorCode);
// Show user-friendly message
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(userMessage)),
);
// Log technical details
print('Technical error: $error');
print('Error code: ${result.errorCode}');
print('Retryable: ${authManager.isErrorRetryable(result.errorCode)}');
}
Common Error Codes
Error Code | User-Friendly Message | Retryable |
---|---|---|
user-not-found |
No account found with this email address. | β |
wrong-password |
Incorrect password. Please try again. | β |
invalid-email |
Please enter a valid email address. | β |
user-disabled |
This account has been disabled. | β |
too-many-requests |
Too many failed attempts. Please try again later. | β |
email-already-in-use |
An account with this email already exists. | β |
weak-password |
Please choose a stronger password. | β |
network-request-failed |
Network connection error. | β |
Advanced Features π§
Session Management
// Set session timeout
authManager.setSessionTimeout(Duration(hours: 2));
// Check session status
bool isValid = await authManager.validateSession();
Duration? remaining = authManager.getRemainingSessionTime();
bool nearExpiry = authManager.isSessionNearExpiry();
// Refresh tokens
await authManager.refreshToken();
String? token = await authManager.getIdToken(forceRefresh: true);
Biometric Authentication
// Check if biometric auth is available
bool available = await authManager.isBiometricAvailable();
if (available) {
// Enable biometric auth
await authManager.enableBiometricAuth();
// Authenticate with biometric
final result = await authManager.authenticateWithBiometric(
localizedFallbackTitle: 'Use Passcode',
cancelButtonText: 'Cancel',
);
}
Analytics and Monitoring
// Get authentication statistics
Map<String, Object?> stats = authManager.getAuthStats();
print('Sign-in attempts: ${stats['signIn_attempts']}');
print('Success rate: ${stats['success_rate']}');
// Reset statistics
authManager.resetAuthStats();
// Enable debug logging
authManager.enableDebugLogging(true);
// Get debug information
Map<String, Object?> debugInfo = authManager.getDebugInfo();
Configuration
// Configure authentication settings
authManager.configure(
sessionTimeout: Duration(hours: 24),
enableBiometric: true,
enableRememberMe: true,
enabledProviders: ['google.com', 'apple.com', 'password'],
providerConfigs: {
'google': {'scopes': ['email', 'profile']},
'apple': {'scopes': ['email', 'name']},
},
);
// Get current configuration
Map<String, Object?> config = authManager.getConfiguration();
// Reset to defaults
authManager.resetConfiguration();
Testing π§ͺ
The package is designed with testing in mind:
// Create mock auth manager for testing
class MockAuthManager implements IAuthManager {
// Implement interface methods for testing
}
// Use in tests
testWidgets('Login page test', (tester) async {
final mockAuthManager = MockAuthManager();
await tester.pumpWidget(
MaterialApp(
home: LoginPage(authManager: mockAuthManager),
),
);
// Test authentication flow
});
Best Practices π
1. Proper Initialization
class _MyAppState extends State<MyApp> {
IAuthManager? _authManager;
bool _isInitializing = true;
@override
void initState() {
super.initState();
_initializeAuth();
}
Future<void> _initializeAuth() async {
_authManager = await FirebaseAuthManager.create();
if (mounted) {
setState(() {
_isInitializing = false;
});
}
}
@override
void dispose() {
_authManager?.dispose(); // Important: dispose resources
super.dispose();
}
}
2. Error Handling
Future<void> _handleAuthOperation(Future<AuthResultModel> operation) async {
try {
final result = await operation;
if (result.success) {
// Handle success
_showSuccess('Operation completed successfully');
} else {
// Handle failure with user-friendly message
final userMessage = authManager.getUserFriendlyErrorMessage(result.errorCode);
_showError(userMessage);
}
} catch (e) {
// Handle unexpected errors
_showError('An unexpected error occurred');
}
}
3. State Management
// Use StreamBuilder for reactive UI
StreamBuilder<AuthStateModel>(
stream: authManager.authStateStream,
builder: (context, snapshot) {
final state = snapshot.data ?? AuthStateModel.initial();
if (state.isLoading) {
return LoadingWidget();
}
if (state.hasError) {
return ErrorWidget(error: state.error);
}
return state.isAuthenticated
? AuthenticatedView(user: state.user!)
: UnauthenticatedView();
},
);
4. Security Considerations
// Always validate inputs
if (!authManager.validateEmail(email)) {
return _showError('Please enter a valid email address');
}
// Use strong password validation
if (!authManager.validatePasswordStrength(password)) {
return _showError('Password does not meet security requirements');
}
// Enable session timeout for security
authManager.setSessionTimeout(Duration(hours: 1));
// Use biometric authentication when available
if (await authManager.isBiometricAvailable()) {
await authManager.enableBiometricAuth();
}
Migration Guide π
From firebase_auth package
If you're migrating from the firebase_auth package:
// Before (firebase_auth)
final userCredential = await FirebaseAuth.instance.signInWithEmailAndPassword(
email: email,
password: password,
);
final user = userCredential.user;
// After (app_auth_manager)
final result = await authManager.signInWithEmailAndPassword(
email: email,
password: password,
);
if (result.success) {
final user = result.user;
}
Troubleshooting π§
Common Issues
-
Firebase not initialized
// Ensure Firebase is initialized before using auth manager await Firebase.initializeApp();
-
Google Sign-In not working
- Check SHA-1 fingerprint in Firebase Console
- Verify
google-services.json
is in correct location - Ensure Google Sign-In is enabled in Firebase Console
-
Apple Sign-In not working
- Enable Sign in with Apple in Apple Developer Console
- Add Sign in with Apple capability in Xcode
- Verify bundle identifier matches
-
State not updating
// Ensure you're listening to the auth state stream StreamBuilder<AuthStateModel>( stream: authManager.authStateStream, builder: (context, snapshot) { // Handle state changes }, );
Contributing π€
Contributions are welcome! Please read our Contributing Guide for details on our code of conduct and the process for submitting pull requests.
License π
This project is licensed under the MIT License - see the LICENSE file for details.
Changelog π
See CHANGELOG.md for a detailed list of changes and version history.
Support π¬
- Documentation: API Reference
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Roadmap πΊοΈ
Made with β€οΈ by Bahrican Yesil
Libraries
- app_auth_manager
- A comprehensive Flutter app authentication manager that provides authentication support with Firebase Auth, Google Sign-In, Apple Sign-In, and other authentication methods.