Planned Update
This module is in the queue for a documentation refresh.
Auth Component
1. Requirements Document
Overview
A comprehensive authentication wrapper that handles multiple authentication strategies (OAuth2.0, SSO, email/password) while abstracting away complexity like token storage, refresh token rotation, and request retries.
User Stories
- As a Developer, I want to easily switch between authentication providers (e.g. Google, Apple, Email) with a unified API.
- As a Developer, I want the app to automatically refresh expired access tokens without user intervention.
- As a Developer, I want failed requests due to token expiration to automatically retry after a successful refresh.
- As a User, I want my session to persist securely across app restarts.
Functional Requirements
- Multiple Auth Strategies: Support for
OAuth2(via webview/native),SSO(SAML/OIDC), andCredential(username/pass) flows. - Token Management: Securely store Access & Refresh tokens using platform-specific secure storage (Keychain/Keystore).
- Auto-Refresh: Intercept 401 errors, lock the request queue, refresh the token, and retry pending requests.
- Session State: Provide a reactive stream/provider for the current user's authentication state (
authenticated,guest,loading).
2. Technical Document
Architecture
System Architecture
The AuthManager acts as the central coordinator. It holds the current user state, manages the interaction with the Secure Storage for persistence, and injects itself into the HTTP Client to handle request interception for token refreshes.
API Design
AuthManager Usage
// Initialize the AuthManager with your config
final authConfig = AuthConfig(
baseUrl: 'https://api.example.com',
loginEndpoint: '/auth/login',
refreshEndpoint: '/auth/refresh',
clientId: 'your-client-id',
);
final authManager = AuthManager(
storage: SecureTokenStorage(),
client: DioClient(), // or http.Client
config: authConfig,
);
// Login with Password
await authManager.login(
AuthType.password,
payload: {'email': 'user@example.com', 'password': '...'}
);
// Login with OAuth (triggers native/webview flow)
await authManager.login(AuthType.google);
// Listen to auth state changes
authManager.authState.listen((state) {
if (state == AuthState.authenticated) {
router.go('/home');
} else {
router.go('/login');
}
});Token Refresh Interceptor
The library includes an interceptor that automatically handles 401s:
class AuthInterceptor extends Interceptor {
final AuthManager manager;
@override
void onError(DioException err, ErrorInterceptorHandler handler) async {
if (err.response?.statusCode == 401) {
// 1. Lock queue
// 2. Refresh token
final newToken = await manager.refreshToken();
// 3. Retry original request with new token
final opts = err.requestOptions;
opts.headers['Authorization'] = 'Bearer $newToken';
final response = await dio.fetch(opts);
handler.resolve(response);
} else {
handler.next(err);
}
}
}