hng_firebase_auth 1.0.1 copy "hng_firebase_auth: ^1.0.1" to clipboard
hng_firebase_auth: ^1.0.1 copied to clipboard

A simple and modular Firebase authentication wrapper for Flutter, supporting email/password, Google, and Apple sign-in.

๐Ÿ” HNG Firebase Auth SDK #

A comprehensive, production-ready Firebase Authentication SDK for Flutter with pre-built UI and headless mode support.

Flutter Firebase

โœจ Features #

๐Ÿ”‘ Authentication Providers #

  • โœ… Email/Password - Traditional authentication
  • โœ… Google Sign-In - One-tap Google authentication
  • โœ… Apple Sign-In - Native Apple authentication (iOS)
  • ๐Ÿ”ง Expandable - Easy to add other Firebase providers

๐Ÿ“Š State Management #

Automatically tracks and exposes three core authentication states:

  • Authenticated - User is signed in
  • Unauthenticated - User is signed out
  • TokenExpired - Session expired, re-authentication needed
  • Loading - Authentication operation in progress

โš™๏ธ Configuration System #

Flexible configuration object to enable/disable specific login methods:

AuthConfig(
  providers: {
    'email': true,
    'google': true,
    'apple': true,
  },
  autoRefreshToken: true,
  tokenRefreshInterval: 3000000,
)

๐Ÿ›ก๏ธ Error Handling & Logging #

Unified error handling layer with custom exception types:

  • InvalidCredentialsException - Wrong password/email combination
  • UserNotFoundException - Account does not exist
  • EmailAlreadyInUseException - Sign-up conflict
  • WeakPasswordException - Password doesn't meet requirements
  • TokenExpiredException - Session expired
  • NetworkException - Network connectivity issues

All Firebase errors are automatically mapped to these custom types.

๐ŸŽจ UI Flexibility #

Default Mode (Plug-and-Play)

Pre-built widget that renders a complete login form based on configuration:

AuthWidget(
  onSuccess: () => print('Login successful!'),
  onError: (error) => print('Error: ${error.message}'),
)

Headless Mode (Custom UI)

Expose methods and streams for complete UI control:

final authProvider = Provider.of<AuthProvider>(context);

// Methods
await authProvider.signInWithEmail(email, password);
await authProvider.signInWithGoogle();
await authProvider.signInWithApple();
await authProvider.signOut();

// State access
final user = authProvider.user;
final isAuthenticated = authProvider.isAuthenticated;
final state = authProvider.state;

// Stream access (via SDK)
final authStream = firebaseAuthSDK.authStatusStream;

๐Ÿ“ฆ Installation #

1. Add Dependencies #

Add to your pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter
  firebase_core: ^2.32.0
  firebase_auth: ^4.20.0
  google_sign_in: ^6.1.5
  sign_in_with_apple: ^5.0.0
  provider: ^6.1.1

Run:

flutter pub get

2. Configure Firebase #

Generate Firebase Options

# Install FlutterFire CLI
dart pub global activate flutterfire_cli

# Configure Firebase
flutterfire configure

Initialize Firebase in main.dart

import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  runApp(const MyApp());
}

3. Platform-Specific Setup #

iOS Configuration

  1. Add GoogleService-Info.plist to ios/Runner/
  2. Configure URL schemes in Info.plist:
<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>YOUR_REVERSED_CLIENT_ID</string>
    </array>
  </dict>
</array>
  1. For Sign In with Apple, ensure Runner.entitlements includes:
<key>com.apple.developer.applesignin</key>
<array>
  <string>Default</string>
</array>

Android Configuration

  1. Add google-services.json to android/app/
  2. Update android/build.gradle:
dependencies {
    classpath 'com.google.gms:google-services:4.4.0'
}
  1. Update android/app/build.gradle:
apply plugin: 'com.google.gms.google-services'

4. Secrets Configuration #

This project uses a secrets file to keep sensitive keys out of source control.

  1. Create a new file lib/firebase_secrets.dart
  2. Add your Firebase keys (found in your GoogleService-Info.plist or Firebase Console):
class FirebaseSecrets {
  static const String iosApiKey = 'YOUR_IOS_API_KEY';
  static const String iosAppId = 'YOUR_IOS_APP_ID';
  static const String iosMessagingSenderId = 'YOUR_IOS_SENDER_ID';
  static const String iosProjectId = 'YOUR_PROJECT_ID';
  static const String iosStorageBucket = 'YOUR_STORAGE_BUCKET';
  static const String iosBundleId = 'YOUR_BUNDLE_ID';
}

Note: This file is ignored by git to protect your credentials.

๐Ÿš€ Quick Start #

Using Default Mode (Pre-built UI) #

import 'package:provider/provider.dart';
import 'package:hng_firebase_auth/src/providers/auth_provider.dart';
import 'package:hng_firebase_auth/src/ui/auth_widget.dart';
import 'package:hng_firebase_auth/src/core/auth_config.dart';

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (_) => AuthProvider(
        config: AuthConfig(
          providers: {
            'email': true,
            'google': true,
            'apple': true,
          },
        ),
      ),
      child: MaterialApp(
        home: LoginScreen(),
      ),
    );
  }
}

class LoginScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: AuthWidget(
          onSuccess: () {
            Navigator.pushReplacement(
              context,
              MaterialPageRoute(builder: (_) => HomeScreen()),
            );
          },
          onError: (error) {
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text(error.message)),
            );
          },
        ),
      ),
    );
  }
}

Using Headless Mode (Custom UI) #

import 'package:provider/provider.dart';
import 'package:hng_firebase_auth/src/providers/auth_provider.dart';

class CustomLoginScreen extends StatefulWidget {
  @override
  _CustomLoginScreenState createState() => _CustomLoginScreenState();
}

class _CustomLoginScreenState extends State<CustomLoginScreen> {
  final _emailController = TextEditingController();
  final _passwordController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    final authProvider = Provider.of<AuthProvider>(context);

    return Scaffold(
      appBar: AppBar(title: Text('Custom Login')),
      body: Padding(
        padding: EdgeInsets.all(16),
        child: Column(
          children: [
            // Display current user
            if (authProvider.isAuthenticated)
              Text('Logged in as: ${authProvider.user?.email}'),
            
            // Email field
            TextField(
              controller: _emailController,
              decoration: InputDecoration(labelText: 'Email'),
            ),
            
            // Password field
            TextField(
              controller: _passwordController,
              decoration: InputDecoration(labelText: 'Password'),
              obscureText: true,
            ),
            
            SizedBox(height: 16),
            
            // Sign in button
            ElevatedButton(
              onPressed: authProvider.isLoading ? null : () async {
                try {
                  await authProvider.signInWithEmail(
                    _emailController.text,
                    _passwordController.text,
                  );
                } catch (e) {
                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(content: Text('Error: $e')),
                  );
                }
              },
              child: authProvider.isLoading
                  ? CircularProgressIndicator()
                  : Text('Sign In'),
            ),
            
            // Google Sign In
            ElevatedButton.icon(
              onPressed: () => authProvider.signInWithGoogle(),
              icon: Icon(Icons.g_mobiledata),
              label: Text('Sign in with Google'),
            ),
            
            // Apple Sign In (iOS only)
            if (Platform.isIOS)
              ElevatedButton.icon(
                onPressed: () => authProvider.signInWithApple(),
                icon: Icon(Icons.apple),
                label: Text('Sign in with Apple'),
              ),
            
            // Sign out button
            if (authProvider.isAuthenticated)
              ElevatedButton(
                onPressed: () => authProvider.signOut(),
                child: Text('Sign Out'),
              ),
          ],
        ),
      ),
    );
  }
}

๐Ÿ“– API Reference #

AuthProvider #

The main provider class for managing authentication state.

Properties

AuthStatus status          // Current authentication status
AuthState state            // Current state (authenticated/unauthenticated/etc)
AuthUser? user             // Current user object (null if not authenticated)
Exception? error           // Last error that occurred
bool isAuthenticated       // True if user is signed in
bool isLoading             // True if operation in progress

Methods

Future<void> signInWithEmail(String email, String password)
Future<void> signUpWithEmail(String email, String password)
Future<void> signInWithGoogle()
Future<void> signInWithApple()
Future<void> signOut()
AuthUser? getCurrentUser()

AuthConfig #

Configuration object for the SDK.

AuthConfig({
  Map<String, bool> providers = const {
    'email': true,
    'google': true,
    'apple': true,
  },
  bool autoRefreshToken = true,
  int tokenRefreshInterval = 3000000, // milliseconds
})

AuthState Enum #

enum AuthState {
  authenticated,      // User is signed in
  unauthenticated,   // User is signed out
  tokenexpired,      // Session expired
  loading,           // Operation in progress
}

AuthUser #

User information object.

class AuthUser {
  final String uid;
  final String? email;
  final String? displayName;
  final String? photoUrl;
  final String provider;  // 'email', 'google', or 'apple'
}

๐Ÿšจ Error Code Documentation #

All authentication errors are mapped to custom exception types:

Error Code Exception Class Message Common Cause
INVALID_CREDENTIALS InvalidCredentialsException Wrong email or password Incorrect login credentials
USER_NOT_FOUND UserNotFoundException Account does not exist Email not registered
EMAIL_IN_USE EmailAlreadyInUseException Email already registered Sign-up with existing email
WEAK_PASSWORD WeakPasswordException Password must be 6+ characters Password too short
TOKEN_EXPIRED TokenExpiredException Session expired, please login again Auth token expired
NETWORK_ERROR NetworkException Check your internet connection No network connectivity
UNKNOWN_ERROR AuthException Custom error message Other Firebase errors

Error Handling Example #

try {
  await authProvider.signInWithEmail(email, password);
} on InvalidCredentialsException catch (e) {
  print('Wrong password: ${e.message}');
} on UserNotFoundException catch (e) {
  print('User not found: ${e.message}');
} on NetworkException catch (e) {
  print('Network error: ${e.message}');
} on AuthException catch (e) {
  print('Auth error (${e.code}): ${e.message}');
}

๐Ÿ“ Project Structure #

lib/
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ core/
โ”‚   โ”‚   โ”œโ”€โ”€ auth_config.dart      # Configuration class
โ”‚   โ”‚   โ”œโ”€โ”€ auth_sdk.dart         # Core SDK implementation
โ”‚   โ”‚   โ””โ”€โ”€ auth_state.dart       # State & user models
โ”‚   โ”œโ”€โ”€ exceptions/
โ”‚   โ”‚   โ””โ”€โ”€ auth_exceptions.dart  # Custom exception types
โ”‚   โ”œโ”€โ”€ providers/
โ”‚   โ”‚   โ””โ”€โ”€ auth_provider.dart    # ChangeNotifier provider
โ”‚   โ””โ”€โ”€ ui/
โ”‚       โ””โ”€โ”€ auth_widget.dart      # Pre-built UI component
โ”œโ”€โ”€ firebase_options.dart         # Firebase configuration
โ””โ”€โ”€ main.dart                     # Example app

โš ๏ธ Important Notes #

Sign In with Apple - iOS Simulator Limitation #

Sign In with Apple DOES NOT work on iOS Simulators! This is an Apple limitation.

  • โŒ Simulator: Will fail (expected behavior)
  • โœ… Real Device: Works correctly

To test Sign In with Apple, you must use a physical iOS device.

See APPLE_SIGNIN_NOTES.md for detailed information.

Firebase Console Setup #

Ensure you've enabled authentication providers in Firebase Console:

  1. Go to Firebase Console
  2. Select your project
  3. Navigate to Authentication โ†’ Sign-in method
  4. Enable Email/Password, Google, and Apple providers

๐Ÿงช Testing #

Run the example app:

flutter run

The example demonstrates both Default (pre-built UI) and Headless modes in a tabbed interface.

๐Ÿ“ Example App #

The example app (lib/main.dart) demonstrates:

  • โœ… Default mode with AuthWidget
  • โœ… Headless mode with custom UI
  • โœ… Stream-based state management
  • โœ… Error handling
  • โœ… All three authentication providers

๐Ÿค Contributing #

This SDK is designed to be expandable. To add new Firebase providers:

  1. Add the provider package to pubspec.yaml
  2. Add sign-in method to FirebaseAuthSDK class
  3. Add provider method to AuthProvider
  4. Update AuthConfig to include the new provider
  5. Update UI components as needed

๐Ÿ“„ License #

This project is part of the HNG internship task.

๐Ÿ”— Resources #

โœ… Implementation Checklist #

  • โœ… Email/Password authentication
  • โœ… Google Sign-In integration
  • โœ… Apple Sign-In integration
  • โœ… State management (Authenticated, Unauthenticated, TokenExpired)
  • โœ… Configuration system for providers
  • โœ… Custom error handling with all required exception types
  • โœ… Default mode (plug-and-play UI)
  • โœ… Headless mode (exposed methods and streams)
  • โœ… Example app with both modes
  • โœ… Complete README with API reference
  • โœ… Error code documentation
  • โœ… Platform-specific setup instructions
  • โœ… Firebase integration
  • โœ… Automatic token refresh
  • โœ… Stream-based state updates

Made with โค๏ธ for HNG Internship

0
likes
60
points
23
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A simple and modular Firebase authentication wrapper for Flutter, supporting email/password, Google, and Apple sign-in.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

cupertino_icons, firebase_auth, firebase_core, flutter, google_sign_in, provider, sign_in_with_apple

More

Packages that depend on hng_firebase_auth