Auth SDK
A flexible, Firebase-powered authentication SDK for Flutter that supports both pre-built UI and headless (custom UI) modes.
π Features
- β Multiple Auth Providers: Email/Password, Google Sign-In, (Apple Sign-In coming soon)
- β Dual Modes: Pre-built UI widget or headless mode for complete customization
- β State Management Flexibility: Use with BLoC, Provider, Riverpod, GetX, or plain setState
- β Automatic State Tracking: Authenticated, Unauthenticated, TokenExpired, Loading, Error
- β Custom Exception Handling: Clear, typed exceptions for all error scenarios
- β Configurable UI: Enable/disable specific auth methods in pre-built UI
- β Stream-based: Reactive auth state changes
- β Type-safe: Full TypeScript-like null safety
π± Screenshots
Pre-built UI Mode
![]() |
| Sign In |
![]() |
![]() |
![]() |
| Custom Login | Custom Sign Up | Mode Selection |
π¦ Installation
Add this to your pubspec.yaml:
dependencies:
auth_sdk:
path: ../auth_sdk # Or your published package path
firebase_core: ^4.2.1
firebase_auth: ^6.1.2
flutter_bloc: ^9.1.1 # Only needed if using pre-built UI mode
Then run:
flutter pub get
π Quick Start
1. Initialize Firebase
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
2. Choose Your Mode
Option A: Pre-built UI Mode (Fastest Setup)
import 'package:auth_sdk/auth_sdk.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
final authService = FirebaseAuthService();
final authCubit = AuthCubit(authService);
return BlocProvider<AuthCubit>(
create: (_) => authCubit,
child: MaterialApp(
home: BlocBuilder<AuthCubit, AuthState>(
builder: (context, state) {
if (state.status == AuthStatus.authenticated) {
return HomeScreen();
}
return AuthWidget(
config: AuthConfig(
enableEmail: true,
enableGoogle: true,
enableApple: false,
),
);
},
),
),
);
}
}
Option B: Headless Mode (Full Control)
import 'package:auth_sdk/auth_sdk.dart';
class CustomLoginScreen extends StatefulWidget {
@override
State<CustomLoginScreen> createState() => _CustomLoginScreenState();
}
class _CustomLoginScreenState extends State<CustomLoginScreen> {
late final AuthRepository _authRepository;
AuthUser? _currentUser;
@override
void initState() {
super.initState();
final authService = FirebaseAuthService();
_authRepository = AuthRepository(authService);
// Listen to auth state changes
_authRepository.authStateStream.listen((user) {
setState(() => _currentUser = user);
});
}
Future<void> _signIn() async {
try {
await _authRepository.signInWithEmail(email, password);
} on InvalidCredentialsException catch (e) {
// Handle error
print(e.message);
}
}
@override
Widget build(BuildContext context) {
if (_currentUser != null) {
return HomeScreen();
}
return Scaffold(
body: YourCustomUI(onSignIn: _signIn),
);
}
}
π API Reference
AuthRepository (Headless Mode)
Methods
| Method | Description | Throws |
|---|---|---|
signInWithEmail(email, password) |
Sign in with email/password | InvalidCredentialsException, UserNotFoundException, NetworkException |
signUpWithEmail(email, password) |
Create new account | EmailAlreadyInUseException, WeakPasswordException, NetworkException |
signInWithGoogle() |
Sign in with Google | NetworkException |
signOut() |
Sign out current user | - |
getIdToken({refresh}) |
Get user's ID token | TokenExpiredException |
Streams
| Stream | Type | Description |
|---|---|---|
authStateStream |
Stream<AuthUser?> |
Emits current auth user or null |
AuthCubit (UI Mode)
Methods
| Method | Description |
|---|---|
signInWithEmail(email, password) |
Sign in with email/password |
signUpWithEmail(email, password) |
Create new account |
signInWithGoogle() |
Sign in with Google |
signOut() |
Sign out current user |
States
enum AuthStatus {
authenticated, // User is logged in
unauthenticated, // User is logged out
loading, // Auth operation in progress
error, // An error occurred
tokenExpired, // User's session expired
}
AuthConfig
Configure which auth methods to show in pre-built UI:
// All methods enabled
AuthConfig.defaultConfig
// Email only
AuthConfig.emailOnly
// Social only (Google + Apple)
AuthConfig.socialOnly
// Custom configuration
AuthConfig(
enableEmail: true,
enableGoogle: true,
enableApple: false,
)
β Error Handling
The SDK provides typed exceptions for clear error handling:
| Exception | Code | Description |
|---|---|---|
InvalidCredentialsException |
invalid-credentials |
Wrong email/password combination |
UserNotFoundException |
user-not-found |
Account doesn't exist |
EmailAlreadyInUseException |
email-in-use |
Email already registered |
WeakPasswordException |
password-not-strong |
Password doesn't meet requirements |
TokenExpiredException |
token-expired |
User's session expired |
NetworkException |
network-error |
Network connectivity issue |
Example Error Handling
try {
await authRepository.signInWithEmail(email, password);
} on InvalidCredentialsException catch (e) {
showError('Wrong email or password');
} on UserNotFoundException catch (e) {
showError('Account not found');
} on NetworkException catch (e) {
showError('Check your internet connection');
} catch (e) {
showError('An unexpected error occurred');
}
π¨ UI Customization (Pre-built Widget)
The AuthWidget provides a clean, Material Design interface. Customize it using:
AuthWidget(
config: AuthConfig(
enableEmail: true,
enableGoogle: true,
enableApple: false,
),
)
π§ Advanced Usage
Custom AuthService Implementation
You can implement your own auth backend:
class CustomAuthService implements AuthService {
@override
Stream<AuthUser?> authStateChanges() {
// Your implementation
}
@override
Future<AuthUser?> signInWithEmail(String email, String password) async {
// Your custom backend logic
}
// Implement other methods...
}
// Use it
final customService = CustomAuthService();
final authRepository = AuthRepository(customService);
Token Management
// Get current user's ID token
final token = await authRepository.getIdToken();
// Force token refresh
final freshToken = await authRepository.getIdToken(refresh: true);
// Use token for API calls
final response = await http.get(
apiUrl,
headers: {'Authorization': 'Bearer $token'},
);
π± Platform Setup
Android
- Add
google-services.jsontoandroid/app/ - Update
android/build.gradle:dependencies { classpath 'com.google.gms:google-services:4.4.0' } - Update
android/app/build.gradle:apply plugin: 'com.google.gms.google-services' defaultConfig { minSdk 23 // Required for Firebase Auth }
iOS
- Add
GoogleService-Info.plisttoios/Runner/ - Update
Info.plistfor Google Sign-In:<key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <string>YOUR_REVERSED_CLIENT_ID</string> </array> </dict> </array>
π Example App
Check the /example folder for complete implementations of both modes:
- UI Mode: Using
AuthWidgetwith BLoC - Headless Mode: Custom UI with
setState
Run the example:
cd example
flutter run
π€ Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
π License
This project is licensed under the MIT License.
π₯ Authors
Onojefemue Oghenemine Emmanuel (EmmanuelO)
π Issues & Support
For issues, feature requests, or questions, please file an issue on GitHub.
Made with β€οΈ for the Flutter community



