voo_authstack_client 0.1.7
voo_authstack_client: ^0.1.7 copied to clipboard
Flutter SDK for Voo AuthStack - a centralized authentication platform. Supports email/password, OAuth providers (Google, GitHub, Microsoft, Apple, Discord), automatic token refresh, and provider linking.
Voo AuthStack Client #
A comprehensive Flutter SDK for Voo AuthStack - a centralized authentication platform. Supports email/password authentication, OAuth providers, automatic token refresh, and provider linking.
Features #
- Email/Password Authentication - Register and login with email and password
- OAuth Providers - Login with Google, GitHub, Microsoft, Apple, Discord
- Centralized OAuth - AuthStack handles OAuth app configuration, no OAuth credentials needed
- Provider Credentials - Get provider access tokens to call GitHub API, Google API, etc.
- Token Management - Automatic token storage and refresh
- Provider Linking - Link/unlink multiple OAuth providers to a single account
- Dio Interceptor - Automatic token refresh with request queuing
- Type Safe - Fully typed with strong type constraints
- Clean Architecture - Following best practices with VooCore integration
Installation #
Add to your pubspec.yaml:
dependencies:
voo_authstack_client: ^0.1.3
Or for local development in the VooFlutter monorepo:
dependencies:
voo_authstack_client:
path: packages/dev/voo_authstack_client
Quick Start #
1. Initialize the Service #
import 'package:voo_authstack_client/voo_authstack_client.dart';
final authService = VooAuthstackService(
config: VooAuthstackConfig(
baseUrl: 'https://api.authstack.voostack.com',
),
);
// Initialize (checks for stored tokens)
await authService.initialize();
2. Register a New User #
try {
final result = await authService.register(
email: 'user@example.com',
password: 'securePassword123',
firstName: 'John',
lastName: 'Doe',
);
print('Welcome, ${result.user.fullName}!');
} on VooAuthstackException catch (e) {
print('Registration failed: ${e.message}');
}
3. Login with Email/Password #
try {
final result = await authService.loginWithEmail(
email: 'user@example.com',
password: 'securePassword123',
);
print('Logged in as ${result.user.email}');
} on VooAuthstackException catch (e) {
if (e.code == 'invalid-credentials') {
print('Invalid email or password');
}
}
4. Login with OAuth Provider #
// With access token from OAuth provider
final result = await authService.loginWithOAuthToken(
provider: OAuthProvider.google,
token: googleAccessToken,
);
// With authorization code
final result = await authService.loginWithOAuthCode(
provider: OAuthProvider.github,
code: authorizationCode,
redirectUri: 'https://yourapp.com/callback',
);
5. Listen to Auth State Changes #
authService.statusStream.listen((status) {
switch (status) {
case AuthStatus.authenticated:
print('User is logged in');
break;
case AuthStatus.unauthenticated:
print('User is logged out');
break;
case AuthStatus.authenticating:
print('Login in progress...');
break;
case AuthStatus.refreshing:
print('Refreshing token...');
break;
case AuthStatus.error:
print('Authentication error');
break;
}
});
authService.userStream.listen((user) {
if (user != null) {
print('Current user: ${user.fullName}');
}
});
OAuth Providers #
Supported OAuth providers:
| Provider | Enum Value |
|---|---|
OAuthProvider.google |
|
| GitHub | OAuthProvider.github |
| Microsoft | OAuthProvider.microsoft |
| Apple | OAuthProvider.apple |
| Discord | OAuthProvider.discord |
Provider Linking #
Link multiple OAuth providers to a single account:
// Get linked providers
final providers = await authService.getLinkedProviders();
for (final provider in providers) {
print('${provider.providerType}: ${provider.email}');
}
// Link a new provider
final linked = await authService.linkProviderWithToken(
provider: OAuthProvider.github,
token: githubAccessToken,
);
print('Linked ${linked.providerType}');
// Unlink a provider
await authService.unlinkProvider(OAuthProvider.github);
Centralized OAuth Flow #
AuthStack handles OAuth app configuration centrally, so you don't need your own OAuth credentials. Use getProviderAuthUrl() to start an OAuth flow:
// Get the OAuth authorization URL for GitHub
final authUrl = await authService.getProviderAuthUrl(
provider: OAuthProvider.github,
redirectUri: 'https://yourapp.com/oauth/callback',
);
// Redirect user to authUrl.authorizationUrl
// After authorization, use the code to link the provider
final code = getCodeFromCallback(); // Your callback handling
final linked = await authService.linkProviderWithCode(
provider: OAuthProvider.github,
code: code,
redirectUri: 'https://yourapp.com/oauth/callback',
);
Provider Credentials #
After linking an OAuth provider, get the provider's access token to make API calls:
// Get GitHub credentials to interact with GitHub API
final credentials = await authService.getProviderCredentials(
OAuthProvider.github,
);
// Check if token is expired
if (credentials.isExpired) {
// Re-authenticate with GitHub
}
// Use credentials.accessToken with GitHub API
final github = GitHub(auth: Authentication.withToken(credentials.accessToken));
final repos = await github.repositories.listRepositories().toList();
// Or use with HttpClient
final response = await http.get(
Uri.parse('https://api.github.com/user/repos'),
headers: {'Authorization': 'Bearer ${credentials.accessToken}'},
);
The ProviderCredentials model includes:
accessToken- OAuth access token for the providerrefreshToken- Refresh token (if available)expiresAt- Token expiration timescopes- Granted OAuth scopesisExpired- Whether the token has expired
Token Management #
Custom Token Storage #
Implement TokenStorage for persistent storage:
class SecureTokenStorage implements TokenStorage {
final FlutterSecureStorage _storage = FlutterSecureStorage();
@override
Future<void> saveTokens(AuthTokens tokens) async {
await _storage.write(key: 'auth_tokens', value: jsonEncode(tokens.toJson()));
}
@override
Future<AuthTokens?> getTokens() async {
final data = await _storage.read(key: 'auth_tokens');
if (data == null) return null;
return AuthTokens.fromJson(jsonDecode(data));
}
@override
Future<void> deleteTokens() async {
await _storage.delete(key: 'auth_tokens');
}
@override
Future<bool> hasTokens() async {
return await _storage.containsKey(key: 'auth_tokens');
}
}
// Use custom storage
final authService = VooAuthstackService(
config: VooAuthstackConfig(baseUrl: 'https://api.authstack.voostack.com'),
tokenStorage: SecureTokenStorage(),
);
Auto-Refresh Interceptor #
Add the interceptor to your Dio instance for automatic token refresh:
final dio = Dio();
dio.interceptors.add(AuthInterceptor(
authService: authService,
refreshBuffer: Duration(minutes: 5), // Refresh 5 min before expiry
));
// All requests will now automatically include auth headers
// and refresh tokens when needed
final response = await dio.get('/api/protected-resource');
Configuration #
VooAuthstackConfig(
// Required
baseUrl: 'https://api.authstack.voostack.com',
// Optional
connectTimeout: Duration(seconds: 30),
receiveTimeout: Duration(seconds: 30),
autoRefreshBuffer: Duration(minutes: 5),
)
Error Handling #
All auth errors throw VooAuthstackException:
try {
await authService.loginWithEmail(email: email, password: password);
} on VooAuthstackException catch (e) {
switch (e.code) {
case 'invalid-credentials':
// Wrong email or password
break;
case 'unauthenticated':
// User not logged in
break;
case 'token-expired':
// Token has expired
break;
case 'refresh-failed':
// Failed to refresh token
break;
case 'network-error':
// Network connectivity issue
break;
case 'email-in-use':
// Email already registered
break;
case 'provider-already-linked':
// OAuth provider already linked
break;
case 'provider-not-linked':
// OAuth provider not linked
break;
default:
print('Error: ${e.message}');
}
}
API Reference #
VooAuthstackService #
| Method | Description |
|---|---|
initialize() |
Check for stored tokens and restore session |
register() |
Register new user with email/password |
loginWithEmail() |
Login with email and password |
loginWithOAuthToken() |
Login with OAuth provider token |
loginWithOAuthCode() |
Login with OAuth authorization code |
refreshToken() |
Manually refresh the access token |
logout() |
Logout and clear tokens |
getCurrentUser() |
Fetch current user info |
getLinkedProviders() |
Get all linked OAuth providers |
linkProviderWithToken() |
Link OAuth provider with token |
linkProviderWithCode() |
Link OAuth provider with code |
unlinkProvider() |
Unlink an OAuth provider |
getProviderAuthUrl() |
Get OAuth authorization URL for a provider |
getProviderCredentials() |
Get access token for a linked provider |
dispose() |
Clean up resources |
Properties #
| Property | Type | Description |
|---|---|---|
status |
AuthStatus |
Current auth status |
currentUser |
UserInfo? |
Current user info |
currentTokens |
AuthTokens? |
Current tokens |
isAuthenticated |
bool |
Whether user is authenticated |
statusStream |
Stream<AuthStatus> |
Auth status changes |
userStream |
Stream<UserInfo?> |
User changes |
authenticatedDio |
Dio |
Dio instance with auth headers |
Example #
See the example folder for a complete sample application demonstrating:
- Email/password registration and login
- OAuth provider authentication
- Auth state management
- Provider linking/unlinking
- Token refresh
Run the example:
cd example
flutter run -d chrome
Architecture #
lib/
├── voo_authstack_client.dart # Main export
└── src/
├── enums/
│ ├── auth_status.dart # Authentication states
│ └── oauth_provider.dart # OAuth provider enum
├── exceptions/
│ └── voo_authstack_exception.dart
├── interceptors/
│ └── auth_interceptor.dart # Auto-refresh interceptor
├── models/
│ ├── auth_result.dart # Login/register result
│ ├── auth_tokens.dart # JWT tokens
│ ├── linked_provider.dart # Linked OAuth provider
│ ├── provider_auth_url.dart # OAuth authorization URL
│ ├── provider_credentials.dart # Provider access token
│ └── user_info.dart # User information
└── services/
├── auth_service.dart # Main auth service
└── token_storage.dart # Token storage interface
Learn More #
License #
MIT License - see LICENSE for details.
Built by VooStack #
Need help with Flutter development or authentication solutions?
VooStack builds enterprise Flutter applications and developer tools. We're here to help with your next project.