app_auth_manager 1.0.6 copy "app_auth_manager: ^1.0.6" to clipboard
app_auth_manager: ^1.0.6 copied to clipboard

A comprehensive Flutter app auth manager package that provides authentication support.

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:

  1. Add your SHA-1 fingerprint to Firebase Console
  2. Download and add google-services.json to android/app/
  3. Update android/build.gradle:
buildscript {
    dependencies {
        classpath 'com.google.gms:google-services:4.3.15'
    }
}
  1. Update android/app/build.gradle:
apply plugin: 'com.google.gms.google-services'

android {
    compileSdkVersion 34

    defaultConfig {
        minSdkVersion 21
        targetSdkVersion 34
    }
}

iOS Configuration:

  1. Download and add GoogleService-Info.plist to ios/Runner/
  2. 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:

  1. Enable Sign in with Apple in Apple Developer Console
  2. Add capability in Xcode: Signing & Capabilities β†’ + Capability β†’ Sign in with Apple
  3. 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 #

  1. Firebase not initialized

    // Ensure Firebase is initialized before using auth manager
    await Firebase.initializeApp();
    
  2. 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
  3. 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
  4. 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 πŸ’¬ #

Roadmap πŸ—ΊοΈ #

  • ❌ Facebook Sign-In implementation
  • ❌ Twitter Sign-In implementation
  • ❌ Microsoft Sign-In implementation
  • ❌ GitHub Sign-In implementation
  • ❌ Phone authentication implementation
  • ❌ Email verification implementation
  • ❌ Password reset implementation
  • ❌ Multi-factor authentication
  • ❌ Enterprise SSO support
  • ❌ Offline authentication caching
  • ❌ Advanced analytics and monitoring
  • ❌ Custom authentication flows

Made with ❀️ by Bahrican Yesil