docs(01): research phase domain
Phase 01: Authentication & Account Basics - Standard stack identified (supabase_flutter v2.12.0) - Architecture patterns documented (Flutter + Supabase) - Pitfalls catalogued (session persistence, auth state, password reset) - Code examples provided from official sources
This commit is contained in:
326
.planning/phases/01-authentication/01-RESEARCH.md
Normal file
326
.planning/phases/01-authentication/01-RESEARCH.md
Normal file
@@ -0,0 +1,326 @@
|
||||
# Phase 1: Authentication & Account Basics - Research
|
||||
|
||||
**Researched:** 2026-01-28
|
||||
**Domain:** Flutter + Supabase Authentication
|
||||
**Confidence:** HIGH
|
||||
|
||||
## Summary
|
||||
|
||||
Sage requires Flutter-based authentication using Supabase as the backend service. The established pattern is to use the `supabase_flutter` package (v2.12.0) which provides comprehensive authentication capabilities including email/password signup, password reset, session persistence, and auth state management. The package handles session persistence using SharedPreferences by default, with optional secure storage support via FlutterSecureStorage for enhanced security.
|
||||
|
||||
**Primary recommendation:** Use supabase_flutter v2.12.0 with default SharedPreferences storage and PKCE flow for secure authentication across Android and web platforms.
|
||||
|
||||
## Standard Stack
|
||||
|
||||
The established libraries/tools for this domain:
|
||||
|
||||
### Core
|
||||
| Library | Version | Purpose | Why Standard |
|
||||
|---------|---------|---------|--------------|
|
||||
| supabase_flutter | ^2.12.0 | Official Supabase client for Flutter | Provides complete auth implementation, session management, and real-time auth state updates |
|
||||
| flutter_secure_storage | ^9.0.0 | Enhanced session security (optional) | Industry standard for storing sensitive data securely on mobile devices |
|
||||
| shared_preferences | ^2.0.0 | Default session persistence | Built-in Supabase storage method, lightweight and reliable |
|
||||
|
||||
### Supporting
|
||||
| Library | Version | Purpose | When to Use |
|
||||
|---------|---------|---------|-------------|
|
||||
| go_router | ^13.0.0 | Navigation management | For handling auth-based routing and redirects |
|
||||
| riverpod | ^2.5.0 | State management | For managing global auth state across the app |
|
||||
|
||||
### Alternatives Considered
|
||||
| Instead of | Could Use | Tradeoff |
|
||||
|------------|-----------|----------|
|
||||
| supabase_flutter | firebase_auth | Firebase would work but Supabase is already decided as project standard, better PostgreSQL integration |
|
||||
| supabase_flutter | custom auth implementation | Custom auth is significantly more complex, security risks, requires implementing session management, password hashing, token refresh manually |
|
||||
|
||||
**Installation:**
|
||||
```bash
|
||||
flutter pub add supabase_flutter flutter_secure_storage
|
||||
```
|
||||
|
||||
## Architecture Patterns
|
||||
|
||||
### Recommended Project Structure
|
||||
```
|
||||
src/
|
||||
├── lib/
|
||||
│ ├── main.dart # Supabase initialization
|
||||
│ ├── core/
|
||||
│ │ ├── constants/
|
||||
│ │ │ └── supabase_constants.dart # Supabase URL and keys
|
||||
│ │ └── errors/
|
||||
│ │ └── auth_exceptions.dart # Custom auth error handling
|
||||
│ ├── features/
|
||||
│ │ └── authentication/
|
||||
│ │ ├── data/
|
||||
│ │ │ └── models/
|
||||
│ │ │ └── auth_user.dart # User model
|
||||
│ │ ├── domain/
|
||||
│ │ │ └── repositories/
|
||||
│ │ │ └── auth_repository.dart # Auth interface
|
||||
│ │ └── presentation/
|
||||
│ │ ├── pages/
|
||||
│ │ │ ├── login_page.dart
|
||||
│ │ │ ├── signup_page.dart
|
||||
│ │ │ └── reset_password_page.dart
|
||||
│ │ └── widgets/
|
||||
│ │ ├── auth_form.dart
|
||||
│ │ └── auth_button.dart
|
||||
│ └── providers/
|
||||
│ └── auth_provider.dart # Global auth state management
|
||||
```
|
||||
|
||||
### Pattern 1: Supabase Initialization
|
||||
**What:** Initialize Supabase at app startup with proper configuration
|
||||
**When to use:** In main.dart before runApp()
|
||||
**Example:**
|
||||
```dart
|
||||
// Source: https://pub.dev/packages/supabase_flutter
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
await Supabase.initialize(
|
||||
url: SUPABASE_URL,
|
||||
anonKey: SUPABASE_ANON_KEY,
|
||||
authOptions: FlutterAuthClientOptions(
|
||||
localStorage: const SharedPreferencesLocalStorage(), // Default, secure enough
|
||||
// For enhanced security on mobile:
|
||||
// localStorage: MySecureStorage(),
|
||||
),
|
||||
);
|
||||
|
||||
runApp(MyApp());
|
||||
}
|
||||
|
||||
final supabase = Supabase.instance.client;
|
||||
```
|
||||
|
||||
### Pattern 2: Auth State Management
|
||||
**What:** Use StreamBuilder or Riverpod to listen to auth state changes
|
||||
**When to use:** Throughout the app for UI updates based on auth state
|
||||
**Example:**
|
||||
```dart
|
||||
// Source: https://supabase.com/docs/reference/dart/auth-onauthstatechange
|
||||
class AuthProvider extends ChangeNotifier {
|
||||
User? _user;
|
||||
User? get user => _user;
|
||||
|
||||
AuthProvider() {
|
||||
supabase.auth.onAuthStateChange.listen((data) {
|
||||
final AuthChangeEvent event = data.event;
|
||||
final Session? session = data.session;
|
||||
|
||||
_user = session?.user;
|
||||
notifyListeners();
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 3: Authentication Methods
|
||||
**What:** Use Supabase auth methods for signup, login, password reset
|
||||
**When to use:** For all auth operations
|
||||
**Example:**
|
||||
```dart
|
||||
// Email signup
|
||||
final AuthResponse res = await supabase.auth.signUp(
|
||||
email: email,
|
||||
password: password,
|
||||
);
|
||||
|
||||
// Email login
|
||||
final AuthResponse res = await supabase.auth.signInWithPassword(
|
||||
email: email,
|
||||
password: password,
|
||||
);
|
||||
|
||||
// Password reset
|
||||
await supabase.auth.resetPasswordForEmail(
|
||||
email,
|
||||
redirectTo: 'http://example.com/account/update-password',
|
||||
);
|
||||
```
|
||||
|
||||
### Anti-Patterns to Avoid
|
||||
- **Manual token management:** Don't store JWT tokens manually or implement custom refresh logic
|
||||
- **Ignoring auth state:** Don't skip onAuthStateChange listener - leads to UI inconsistencies
|
||||
- **Hardcoded credentials:** Never store Supabase keys directly in code - use environment variables
|
||||
|
||||
## Don't Hand-Roll
|
||||
|
||||
Problems that look simple but have existing solutions:
|
||||
|
||||
| Problem | Don't Build | Use Instead | Why |
|
||||
|---------|-------------|-------------|-----|
|
||||
| Session persistence | Custom token storage with SharedPreferences | Supabase built-in session management | Handles token expiration, refresh, security automatically |
|
||||
| Password reset email flow | Custom SMTP + email templates | Supabase resetPasswordForEmail() | Built-in rate limiting, secure token generation, proper email handling |
|
||||
| Auth state management | Manual user state with setState() | onAuthStateChange stream | Automatic updates across all app components |
|
||||
| Error handling | Try-catch for every auth call | AuthException handling | Consistent error messages, proper user feedback |
|
||||
|
||||
**Key insight:** Supabase handles all security-critical aspects like token refresh, session validation, and password reset flow securely. Custom implementations risk security vulnerabilities.
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
### Pitfall 1: Session Not Persisting
|
||||
**What goes wrong:** User gets logged out when app restarts
|
||||
**Why it happens:** Missing localStorage configuration or using EmptyLocalStorage
|
||||
**How to avoid:** Ensure proper initialization with default localStorage
|
||||
**Warning signs:** User must log in every time app launches
|
||||
|
||||
### Pitfall 2: Auth State Not Updating UI
|
||||
**What goes wrong:** UI doesn't reflect login/logout status
|
||||
**Why it happens:** Not listening to onAuthStateChange events
|
||||
**How to avoid:** Always subscribe to auth state changes in app initialization
|
||||
**Warning signs:** User stuck on login screen after successful authentication
|
||||
|
||||
### Pitfall 3: Password Reset Flow Fails
|
||||
**What goes wrong:** Reset links don't work or redirect incorrectly
|
||||
**Why it happens:** Missing redirect URL configuration in Supabase dashboard
|
||||
**How to avoid:** Configure redirect URLs in Authentication > URL Configuration
|
||||
**Warning signs:** Users report broken password reset emails
|
||||
|
||||
### Pitfall 4: Web Service Worker Issues
|
||||
**What goes wrong:** Flutter web app fails to register service worker
|
||||
**Why it happens:** Improper web hosting configuration for password reset callback
|
||||
**How to avoid:** Ensure web server serves correct MIME types for service workers
|
||||
**Warning signs:** Console errors about service worker MIME types
|
||||
|
||||
### Pitfall 5: Environment Variable Exposure
|
||||
**What goes wrong:** Supabase keys exposed in client code
|
||||
**Why it happens:** Hardcoding values instead of using environment variables
|
||||
**How to avoid:** Use flutter_dotenv for local dev, proper CI/CD secrets for production
|
||||
**Warning signs:** Keys visible in compiled code or version control
|
||||
|
||||
## Code Examples
|
||||
|
||||
Verified patterns from official sources:
|
||||
|
||||
### Email Sign Up
|
||||
```dart
|
||||
// Source: https://supabase.com/docs/reference/dart/auth-signup
|
||||
final AuthResponse res = await supabase.auth.signUp(
|
||||
email: 'example@email.com',
|
||||
password: 'example-password',
|
||||
);
|
||||
final Session? session = res.session;
|
||||
final User? user = res.user;
|
||||
```
|
||||
|
||||
### Email Sign In
|
||||
```dart
|
||||
// Source: https://supabase.com/docs/reference/dart/auth-signinwithpassword
|
||||
final AuthResponse res = await supabase.auth.signInWithPassword(
|
||||
email: 'example@email.com',
|
||||
password: 'example-password',
|
||||
);
|
||||
final Session? session = res.session;
|
||||
final User? user = res.user;
|
||||
```
|
||||
|
||||
### Password Reset
|
||||
```dart
|
||||
// Source: https://supabase.com/docs/guides/auth/passwords
|
||||
await supabase.auth.resetPasswordForEmail(
|
||||
'valid.email@supabase.io',
|
||||
redirectTo: 'http://example.com/account/update-password',
|
||||
);
|
||||
```
|
||||
|
||||
### Auth State Listening
|
||||
```dart
|
||||
// Source: https://supabase.com/docs/reference/dart/auth-onauthstatechange
|
||||
final authSubscription = supabase.auth.onAuthStateChange.listen((data) {
|
||||
final AuthChangeEvent event = data.event;
|
||||
final Session? session = data.session;
|
||||
|
||||
switch (event) {
|
||||
case AuthChangeEvent.signedIn:
|
||||
// Navigate to home
|
||||
break;
|
||||
case AuthChangeEvent.signedOut:
|
||||
// Navigate to login
|
||||
break;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Secure Storage Option
|
||||
```dart
|
||||
// Source: https://pub.dev/packages/supabase_flutter
|
||||
class MySecureStorage extends LocalStorage {
|
||||
final storage = FlutterSecureStorage();
|
||||
|
||||
@override
|
||||
Future<void> initialize() async {}
|
||||
|
||||
@override
|
||||
Future<String?> accessToken() async {
|
||||
return storage.read(key: supabasePersistSessionKey);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> persistSession(String persistSessionString) async {
|
||||
return storage.write(key: supabasePersistSessionKey, value: persistSessionString);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> removePersistedSession() async {
|
||||
return storage.delete(key: supabasePersistSessionKey);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## State of the Art
|
||||
|
||||
| Old Approach | Current Approach | When Changed | Impact |
|
||||
|--------------|-----------------|--------------|--------|
|
||||
| Hive-based storage (v1) | SharedPreferences-based storage (v2) | v2.0 release | Simpler, faster app startup, better platform support |
|
||||
| Implicit auth flow | PKCE flow (default in v2) | v2.0 release | More secure for deep links and OAuth |
|
||||
| Manual token refresh | Automatic token refresh | v1.x | Session persistence handled automatically |
|
||||
| SupabaseAuth class | Direct client access | v2.0 release | Cleaner API, no wrapper classes needed |
|
||||
|
||||
**Deprecated/outdated:**
|
||||
- **SupabaseAuth.initialSession**: Use supabase.auth.currentSession instead
|
||||
- **Hive storage**: Replaced with SharedPreferences in v2
|
||||
- **signInWithApple() method**: Removed from core package, use separate sign_in_with_apple package
|
||||
- **Provider enum**: Renamed to OAuthProvider to avoid conflicts
|
||||
|
||||
## Open Questions
|
||||
|
||||
1. **Enhanced Security Requirements**
|
||||
- What we know: FlutterSecureStorage available for enhanced session security
|
||||
- What's unclear: Does Sage require enhanced security for food inventory app sensitivity?
|
||||
- Recommendation: Use SharedPreferences for v1, evaluate FlutterSecureStorage for production
|
||||
|
||||
2. **Email Template Customization**
|
||||
- What we know: Supabase provides default email templates
|
||||
- What's unclear: Does Sage need custom branding for password reset emails?
|
||||
- Recommendation: Use default templates for v1, customize after user feedback
|
||||
|
||||
3. **Rate Limiting Strategy**
|
||||
- What we know: Supabase has built-in rate limiting (2 emails/hour default)
|
||||
- What's unclear: Are these limits sufficient for household app usage patterns?
|
||||
- Recommendation: Monitor and configure custom SMTP if limits are reached
|
||||
|
||||
## Sources
|
||||
|
||||
### Primary (HIGH confidence)
|
||||
- supabase_flutter v2.12.0 documentation - Authentication methods, session management, initialization patterns
|
||||
- Supabase official docs - Password reset flow, email authentication best practices
|
||||
|
||||
### Secondary (MEDIUM confidence)
|
||||
- Flutter Secure Storage package documentation - Enhanced session persistence options
|
||||
- Medium articles on Flutter auth patterns - Real-world implementation patterns (verified with official docs)
|
||||
|
||||
### Tertiary (LOW confidence)
|
||||
- Stack Overflow discussions on specific error scenarios - Limited verification, use with caution
|
||||
|
||||
## Metadata
|
||||
|
||||
**Confidence breakdown:**
|
||||
- Standard stack: HIGH - Based on official Supabase Flutter package documentation
|
||||
- Architecture: HIGH - Verified with multiple official sources and community patterns
|
||||
- Pitfalls: HIGH - Official documentation clearly documents common issues and solutions
|
||||
|
||||
**Research date:** 2026-01-28
|
||||
**Valid until:** 2026-02-27 (30 days for stable authentication libraries)
|
||||
Reference in New Issue
Block a user