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:
Dani B
2026-01-28 00:06:55 -05:00
parent 3e9a698bf2
commit 357e7e2b31

View 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)