Skip to main content

Authentication API Reference

Complete API reference for the authentication feature.

Domain Layer

Entities

AuthUser

Domain entity representing an authenticated user.

Location: lib/features/auth/domain/entities/auth_user.dart

class AuthUser extends Equatable {
final String id;
final String email;
final String? name;
final String? avatarUrl;
final DateTime createdAt;

const AuthUser({
required this.id,
required this.email,
this.name,
this.avatarUrl,
required this.createdAt,
});


List<Object?> get props => [id, email, name, avatarUrl, createdAt];
}

Properties:

PropertyTypeDescription
idStringUnique user identifier (UUID)
emailStringUser's email address
nameString?User's display name (optional)
avatarUrlString?URL to user's avatar image (optional)
createdAtDateTimeAccount creation timestamp

AuthSession

Domain entity representing an authentication session with validation.

Location: lib/features/auth/domain/entities/auth_session.dart

class AuthSession extends Equatable {
final AuthUser user;
final String accessToken;
final String refreshToken;
final DateTime expiresAt;

const AuthSession({
required this.user,
required this.accessToken,
required this.refreshToken,
required this.expiresAt,
});

bool get isValid => DateTime.now().isBefore(expiresAt);


List<Object> get props => [user, accessToken, refreshToken, expiresAt];
}

Properties:

PropertyTypeDescription
userAuthUserThe authenticated user
accessTokenStringJWT access token for API requests
refreshTokenStringJWT refresh token for renewing access
expiresAtDateTimeToken expiration timestamp

Getters:

GetterTypeDescription
isValidboolReturns true if session hasn't expired

Repository Interface

AuthRepository

Abstract interface defining authentication operations.

Location: lib/features/auth/domain/repositories/auth_repository.dart

abstract class AuthRepository {
Future<AuthSession> signInWithEmail({
required String email,
required String password,
});

Future<AuthSession> signUpWithEmail({
required String email,
required String password,
String? name,
});

Future<void> signOut();

Future<AuthUser?> getCurrentUser();

Future<AuthSession?> getCurrentSession();

Future<void> resetPassword({required String email});

Future<void> updateProfile({
String? name,
String? avatarUrl,
});

Stream<AuthUser?> get authStateChanges;
}

Methods:

signInWithEmail
Future<AuthSession> signInWithEmail({
required String email,
required String password,
})

Authenticates user with email and password.

  • Parameters:
    • email: User's email address
    • password: User's password
  • Returns: AuthSession on success
  • Throws:
    • InvalidCredentialsException - Wrong email/password
    • NetworkException - No internet connection
    • AuthException - Other authentication errors
signUpWithEmail
Future<AuthSession> signUpWithEmail({
required String email,
required String password,
String? name,
})

Creates new user account with email and password.

  • Parameters:
    • email: User's email address
    • password: User's password (minimum 6 characters)
    • name: User's display name (optional)
  • Returns: AuthSession on success
  • Throws:
    • EmailAlreadyExistsException - Email already registered
    • WeakPasswordException - Password doesn't meet requirements
    • NetworkException - No internet connection
    • AuthException - Other authentication errors
signOut
Future<void> signOut()

Signs out the current user and clears session.

  • Throws:
    • AuthException - Sign out failed
    • NetworkException - No internet connection
getCurrentUser
Future<AuthUser?> getCurrentUser()

Gets the currently authenticated user.

  • Returns: AuthUser if signed in, null otherwise
  • Throws:
    • AuthException - Failed to get current user
getCurrentSession
Future<AuthSession?> getCurrentSession()

Gets the current authentication session.

  • Returns: AuthSession if session exists, null otherwise
  • Throws:
    • SessionExpiredException - Session has expired
    • AuthException - Failed to get session
resetPassword
Future<void> resetPassword({required String email})

Sends password reset email to user.

  • Parameters:
    • email: User's email address
  • Throws:
    • UserNotFoundException - Email not found
    • NetworkException - No internet connection
    • AuthException - Failed to send reset email
updateProfile
Future<void> updateProfile({
String? name,
String? avatarUrl,
})

Updates user profile information.

  • Parameters:
    • name: New display name (optional)
    • avatarUrl: New avatar URL (optional)
  • Throws:
    • UnauthorizedException - No user signed in
    • NetworkException - No internet connection
    • AuthException - Update failed
authStateChanges
Stream<AuthUser?> get authStateChanges

Stream that emits when authentication state changes.

  • Returns: Stream of AuthUser?
  • Emits:
    • AuthUser when user signs in
    • null when user signs out

Use Cases

SignIn

Email/password sign-in use case with validation.

Location: lib/features/auth/domain/usecases/sign_in.dart

class SignIn {
final AuthRepository _repository;

SignIn(this._repository);

Future<AuthSession> call({
required String email,
required String password,
}) async {
// Validation
if (email.trim().isEmpty) {
throw const AuthException('Email cannot be empty');
}
if (password.isEmpty) {
throw const AuthException('Password cannot be empty');
}
if (!_isValidEmail(email)) {
throw const AuthException('Invalid email format');
}

// Delegate to repository
return await _repository.signInWithEmail(
email: email.trim(),
password: password,
);
}

bool _isValidEmail(String email) {
return RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(email);
}
}

Usage:

final signIn = SignIn(authRepository);
try {
final session = await signIn(
email: 'user@example.com',
password: 'password123',
);
print('Signed in: ${session.user.email}');
} on AuthException catch (e) {
print('Sign in failed: ${e.message}');
}

SignUp

Email/password sign-up use case with validation.

Location: lib/features/auth/domain/usecases/sign_up.dart

class SignUp {
final AuthRepository _repository;
static const int _minimumPasswordLength = 6;

SignUp(this._repository);

Future<AuthSession> call({
required String email,
required String password,
String? name,
}) async {
// Validation
if (email.trim().isEmpty) {
throw const AuthException('Email cannot be empty');
}
if (password.isEmpty) {
throw const AuthException('Password cannot be empty');
}
if (!_isValidEmail(email)) {
throw const AuthException('Invalid email format');
}
if (password.length < _minimumPasswordLength) {
throw AuthException(
'Password must be at least $_minimumPasswordLength characters',
);
}

// Delegate to repository
return await _repository.signUpWithEmail(
email: email.trim(),
password: password,
name: name?.trim(),
);
}

bool _isValidEmail(String email) {
return RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(email);
}
}

SignOut

Sign-out use case.

Location: lib/features/auth/domain/usecases/sign_out.dart

class SignOut {
final AuthRepository _repository;

SignOut(this._repository);

Future<void> call() async {
return await _repository.signOut();
}
}

GetCurrentUser

Get current user use case.

Location: lib/features/auth/domain/usecases/get_current_user.dart

class GetCurrentUser {
final AuthRepository _repository;

GetCurrentUser(this._repository);

Future<AuthUser?> call() async {
return await _repository.getCurrentUser();
}
}

Exceptions

Custom authentication exceptions.

Location: lib/core/errors/auth_exceptions.dart

AuthException

Base exception for all authentication errors.

class AuthException implements Exception {
final String message;
const AuthException(this.message);


String toString() => 'AuthException: $message';
}

InvalidCredentialsException

Thrown when email/password combination is incorrect.

class InvalidCredentialsException extends AuthException {
const InvalidCredentialsException([String? message])
: super(message ?? 'Invalid email or password');
}

EmailAlreadyExistsException

Thrown when attempting to sign up with existing email.

class EmailAlreadyExistsException extends AuthException {
const EmailAlreadyExistsException([String? message])
: super(message ?? 'Email already exists');
}

WeakPasswordException

Thrown when password doesn't meet requirements.

class WeakPasswordException extends AuthException {
const WeakPasswordException([String? message])
: super(message ?? 'Password is too weak');
}

UserNotFoundException

Thrown when user email not found.

class UserNotFoundException extends AuthException {
const UserNotFoundException([String? message])
: super(message ?? 'User not found');
}

UnauthorizedException

Thrown when operation requires authentication.

class UnauthorizedException extends AuthException {
const UnauthorizedException([String? message])
: super(message ?? 'User not authorized');
}

NetworkException

Thrown when network connection fails.

class NetworkException extends AuthException {
const NetworkException([String? message])
: super(message ?? 'Network error occurred');
}

SessionExpiredException

Thrown when session has expired.

class SessionExpiredException extends AuthException {
const SessionExpiredException([String? message])
: super(message ?? 'Session has expired');
}

Presentation Layer

BLoC

AuthBloc

BLoC for managing authentication state.

Location: lib/features/auth/presentation/bloc/auth_bloc.dart

class AuthBloc extends Bloc<AuthEvent, AuthState> {
final SignIn _signIn;
final SignUp _signUp;
final SignOut _signOut;
final GetCurrentUser _getCurrentUser;
final AuthRepository _authRepository;

AuthBloc({
required SignIn signIn,
required SignUp signUp,
required SignOut signOut,
required GetCurrentUser getCurrentUser,
required AuthRepository authRepository,
}) : _signIn = signIn,
_signUp = signUp,
_signOut = signOut,
_getCurrentUser = getCurrentUser,
_authRepository = authRepository,
super(const AuthInitial()) {
on<AuthCheckRequested>(_onAuthCheckRequested);
on<AuthSignInRequested>(_onAuthSignInRequested);
on<AuthSignUpRequested>(_onAuthSignUpRequested);
on<AuthSignOutRequested>(_onAuthSignOutRequested);
on<AuthUserChanged>(_onAuthUserChanged);

// Listen to auth state changes
_authStateSubscription = _authRepository.authStateChanges.listen((user) {
add(AuthUserChanged(user?.id));
});
}


Future<void> close() {
_authStateSubscription?.cancel();
return super.close();
}
}

AuthEvent

Events that can be sent to AuthBloc.

Location: lib/features/auth/presentation/bloc/auth_event.dart

AuthCheckRequested
class AuthCheckRequested extends AuthEvent {}

Check current authentication status on app start.

AuthSignInRequested
class AuthSignInRequested extends AuthEvent {
final String email;
final String password;

const AuthSignInRequested({
required this.email,
required this.password,
});
}

Request sign in with email and password.

AuthSignUpRequested
class AuthSignUpRequested extends AuthEvent {
final String email;
final String password;
final String? name;

const AuthSignUpRequested({
required this.email,
required this.password,
this.name,
});
}

Request sign up with email, password, and optional name.

AuthSignOutRequested
class AuthSignOutRequested extends AuthEvent {}

Request sign out of current session.

AuthUserChanged
class AuthUserChanged extends AuthEvent {
final String? userId;

const AuthUserChanged(this.userId);
}

Internal event triggered when auth state changes.

AuthState

States emitted by AuthBloc.

Location: lib/features/auth/presentation/bloc/auth_state.dart

AuthInitial
class AuthInitial extends AuthState {
const AuthInitial();
}

Initial state before any auth operations.

AuthLoading
class AuthLoading extends AuthState {
const AuthLoading();
}

Authentication operation in progress.

AuthAuthenticated
class AuthAuthenticated extends AuthState {
final AuthUser user;

const AuthAuthenticated(this.user);
}

User is successfully authenticated.

AuthUnauthenticated
class AuthUnauthenticated extends AuthState {
const AuthUnauthenticated();
}

User is not authenticated.

AuthError
class AuthError extends AuthState {
final String message;

const AuthError(this.message);
}

Authentication operation failed with error message.

Configuration

SupabaseConfig

Configuration class for Supabase connection.

Location: lib/core/config/supabase_config.dart

class SupabaseConfig {
SupabaseConfig._(); // Private constructor

static const String supabaseUrl = String.fromEnvironment(
'SUPABASE_URL',
defaultValue: 'http://localhost:54321',
);

static const String supabaseAnonKey = String.fromEnvironment(
'SUPABASE_ANON_KEY',
defaultValue: 'eyJhbGc...', // Local dev key
);

static const bool enableDebugLogging = bool.fromEnvironment(
'SUPABASE_DEBUG',
defaultValue: true,
);
}

Constants:

ConstantTypeDefaultDescription
supabaseUrlStringhttp://localhost:54321Supabase project URL
supabaseAnonKeyStringLocal dev keySupabase anonymous key
enableDebugLoggingbooltrueEnable Supabase debug logs

Environment Variables:

Set via --dart-define flags:

flutter run \
--dart-define=SUPABASE_URL=https://xxx.supabase.co \
--dart-define=SUPABASE_ANON_KEY=your-key \
--dart-define=SUPABASE_DEBUG=false