Skip to content

Authentication

ShipFlutter uses Firebae Authentication as a backend, offering a set of authentication methods that you can use to authenticate your users, in addition to a responsive login page that handles social signin, email-password, anonymous auth, as well as verification and recover flow.

Before starting, make sure you have completed the Firebase setup, including the Firebase Authentication steps.

Features

The authentication module provides the following features:

  1. Multiple sign-in methods (Email/Password, Anonymous, Social)
  2. Secure credential management
  3. Real-time authentication state
  4. Email verification
  5. Password recovery
  6. Account deletion
  7. Social authentication (Google, Apple, Facebook)
  8. Custom claims support
  9. Handles reauthorization dialog

Overview

The authentication module is structured in the following way:

  • Directoryaccount/access
    • auth_view.dart // Responsive login page
    • auth_dialog.dart // Utility dialogs (e.g recover password)
    • auth_route.dart // Navigation logic
    • auth_controller.dart // Business logic and state
    • auth_service.dart // Connector to the Firebase Auth Backend
    • credentials.dart // Model class with user auth data
    • credentials_controller.dart // Observes changes in the credentials
  • Directoryfirebase/
    • Directoryauth/
      • auth_service.dart // Connector to the Firebase Auth Backend

AuthService

The AuthService class (in core/firebase/auth) is the main interface for authentication operations. It provides methods for:

// Initialize the service
final authService = await authService.instance;
// Sign in methods
await authService.signin(email, password);
await authService.signinAnonymously();
await authService.signinWithGoogle();
await authService.signinWithApple();
// Account management
await authService.signup(email, password);
await authService.sendVerifyEmail();
await authService.recoverPassword(email);
await authService.delete(password: 'optional-password');
// Authentication state
final isAuthenticated = authService.isAuthenticated();
final credentials = await authService.getCurrent();
authService.onCredentialsChange().listen((credentials) {
// Handle auth state changes
});

Credentials Model

The Credentials class (in core/account/credentials) represents the user’s authentication state:

class Credentials {
final String id; // User's unique identifier
final String? token; // Authentication token
final CredentialsType type; // anonymous, unverified, or verified
final DateTime createdAt; // Account creation time
final String? name; // User's display name
final String? email; // User's email
final String? phone; // User's phone number
final String? imageUrl; // User's profile image
final Map<String, dynamic>? claims; // Custom claims
}

Error Handling

The UI automatically handles common authentication errors:

void _onError(Object? error) {
if (error is AuthError) {
switch (error.type) {
case AuthErrorType.network:
showError('Check your connection');
case AuthErrorType.invalid:
showError('Invalid credentials');
// ... other error types
}
}
}

AuthView

ShipFlutter provides a responsive and customizable authentication UI that adapts to different screen sizes and orientations. The UI is implemented in the core/account/access module.

Features

  1. Responsive Design

    • Portrait mode for mobile devices
    • Landscape mode for tablets and desktops
    • Adapts to different screen sizes
  2. Multiple Authentication Methods

    • Email/Password form with validation
    • Social login buttons (Google, Apple, Facebook)
    • Anonymous login option with “Skip for now” option
  3. User-Friendly Experience

    • Clear error messages
    • Loading indicators
    • Smooth animations
    • Form validation

Customization

The UI is built with Material Design 3 and automatically adapts to your app’s theme. You can customize:

  1. Colors and Typography

    // In your theme.dart
    final theme = AppTheme(
    // Your theme configuration
    );
  2. Text and Labels

    // In your i18n/en.json
    {
    "auth": {
    "login_title": "Welcome Back",
    "signup_title": "Create Account",
    "email_label": "Email",
    "password_label": "Password",
    // ... other labels
    }
    }
  3. Social Login Providers

    // In your auth_controller.dart
    final socials = [
    AuthEvent.google,
    AuthEvent.apple,
    // ... other providers
    ];

How to use it

You can either use the UI components or the controller directly:

// 1. As a full screen page (recommended)
context.go('/auth');
// 2. As a dialog
showDialog(context: context, builder: (context) => const AuthView());

Security Best Practices

  1. Always Handle Authentication Errors

    • Use the AuthError type to handle specific error cases
    • Provide appropriate user feedback for each error type
  2. Verify Email When Required

    • Check credentials.type to determine verification status
    • Use sendVerifyEmail() for unverified accounts
  3. Secure Token Management

    • Never store tokens in plain text
    • Use the built-in token management system
  4. Regular Reauthorization

    • Use reauthenticate() for sensitive operations
    • Handle requires-recent-login errors appropriately

Error Handling

The authentication module uses the AuthError class which provides specific error types:

enum AuthErrorType {
unknown, // Unexpected errors
network, // Network connectivity issues
invalid, // Invalid credentials
weakPassword, // Password doesn't meet requirements
exists, // Email already in use
}

Handle errors appropriately in your UI:

try {
await authService.signin(email, password);
} on AuthError catch (e) {
switch (e.type) {
case AuthErrorType.network:
showError('Check your internet connection');
case AuthErrorType.invalid:
showError('Invalid email or password');
case AuthErrorType.exists:
showError('Account already exists');
// ... handle other cases
}
}