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