Files
Sage/.planning/phases/01-authentication/01-RESEARCH.md
Dani B 357e7e2b31 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
2026-01-28 00:06:55 -05:00

13 KiB

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:

flutter pub add supabase_flutter flutter_secure_storage

Architecture Patterns

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:

// 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:

// 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:

// 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

// 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

// 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

// 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

// 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

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