Files
minhthu/lib/features/auth
2025-10-28 23:46:07 +07:00
..
fix
2025-10-28 23:46:07 +07:00
2025-10-28 00:09:46 +07:00
2025-10-28 00:09:46 +07:00
fix
2025-10-28 23:46:07 +07:00
2025-10-28 00:09:46 +07:00
2025-10-28 00:09:46 +07:00
2025-10-28 00:09:46 +07:00
2025-10-28 00:09:46 +07:00

Authentication Feature

Complete authentication implementation following clean architecture principles for the warehouse management app.

Architecture Overview

auth/
├── data/                      # Data layer
│   ├── datasources/           # API and local data sources
│   │   └── auth_remote_datasource.dart
│   ├── models/                # Data transfer objects
│   │   ├── login_request_model.dart
│   │   └── user_model.dart
│   ├── repositories/          # Repository implementations
│   │   └── auth_repository_impl.dart
│   └── data.dart             # Barrel export
│
├── domain/                    # Domain layer (business logic)
│   ├── entities/              # Business entities
│   │   └── user_entity.dart
│   ├── repositories/          # Repository interfaces
│   │   └── auth_repository.dart
│   ├── usecases/             # Use cases
│   │   └── login_usecase.dart
│   └── domain.dart           # Barrel export
│
├── presentation/              # Presentation layer (UI)
│   ├── pages/                 # Screen widgets
│   │   └── login_page.dart
│   ├── providers/            # State management
│   │   └── auth_provider.dart
│   ├── widgets/              # Reusable widgets
│   │   └── login_form.dart
│   └── presentation.dart     # Barrel export
│
├── di/                        # Dependency injection
│   └── auth_dependency_injection.dart
│
├── auth.dart                  # Main barrel export
└── README.md                  # This file

Features

Implemented

  • User login with username/password
  • Token storage in secure storage
  • Authentication state management
  • Form validation
  • Error handling with user-friendly messages
  • Loading states
  • Auto-navigation after successful login
  • Check authentication status on app start
  • Logout functionality
  • Token refresh (prepared for future use)

Pending

  • Integration with actual API endpoints
  • Biometric authentication
  • Remember me functionality
  • Password recovery

Data Flow

Login Flow

1. User enters credentials in LoginPage
2. LoginForm validates input
3. AuthNotifier.login() is called
4. LoginUseCase validates and processes request
5. AuthRepository calls AuthRemoteDataSource
6. API response is converted to UserModel
7. Tokens saved to SecureStorage
8. AuthState updated to authenticated
9. Navigation to warehouses page

Logout Flow

1. User triggers logout
2. AuthNotifier.logout() is called
3. LogoutUseCase calls AuthRepository
4. API logout call (optional, can fail)
5. SecureStorage cleared
6. AuthState reset to initial
7. Navigation to login page

Usage

Basic Import

import 'package:minhthu/features/auth/auth.dart';

Using in UI

// In a ConsumerWidget or ConsumerStatefulWidget
class MyWidget extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // Watch auth state
    final authState = ref.watch(authProvider);

    // Check authentication
    if (authState.isAuthenticated) {
      return AuthenticatedView(user: authState.user!);
    }

    // Handle loading
    if (authState.isLoading) {
      return LoadingIndicator();
    }

    // Show error
    if (authState.error != null) {
      return ErrorView(message: authState.error!);
    }

    return LoginView();
  }
}

Perform Login

// In your widget
void handleLogin(String username, String password) {
  ref.read(authProvider.notifier).login(username, password);
}

Perform Logout

void handleLogout() {
  ref.read(authProvider.notifier).logout();
}

Check Auth Status

void checkIfAuthenticated() async {
  await ref.read(authProvider.notifier).checkAuthStatus();
}

Listen to Auth Changes

ref.listen(authProvider, (previous, next) {
  if (next.isAuthenticated) {
    // Navigate to home
    context.go('/home');
  } else if (next.error != null) {
    // Show error snackbar
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text(next.error!)),
    );
  }
});

API Integration

Expected API Response Format

{
  "Value": {
    "userId": "string",
    "username": "string",
    "accessToken": "string",
    "refreshToken": "string"
  },
  "IsSuccess": true,
  "IsFailure": false,
  "Errors": [],
  "ErrorCodes": []
}

Login Request

POST /api/v1/auth/login
{
  "username": "string",
  "password": "string"
}

Logout Request

POST /api/v1/auth/logout
Authorization: Bearer {accessToken}

Refresh Token Request

POST /api/v1/auth/refresh
{
  "refreshToken": "string"
}

State Management

AuthState

class AuthState {
  final UserEntity? user;           // Current user or null
  final bool isAuthenticated;       // Authentication status
  final bool isLoading;             // Loading indicator
  final String? error;              // Error message
}

State Transitions

Initial State → Loading → Authenticated (success)
                       → Error (failure)

Testing

Unit Tests (TODO)

// Test use cases
test('login with valid credentials returns user', () async {
  // Arrange
  final useCase = LoginUseCase(mockRepository);
  final request = LoginRequestModel(
    username: 'testuser',
    password: 'password123',
  );

  // Act
  final result = await useCase(request);

  // Assert
  expect(result.isRight(), true);
});

// Test repository
test('repository saves tokens on successful login', () async {
  // Test implementation
});

Widget Tests (TODO)

testWidgets('login page shows form fields', (tester) async {
  await tester.pumpWidget(
    ProviderScope(
      child: MaterialApp(home: LoginPage()),
    ),
  );

  expect(find.byType(TextField), findsNWidgets(2));
  expect(find.text('Username'), findsOneWidget);
  expect(find.text('Password'), findsOneWidget);
});

Error Handling

Validation Errors

  • Empty username/password
  • Username too short (< 3 characters)
  • Password too short (< 6 characters)

Network Errors

  • Connection timeout
  • No internet connection
  • Server unreachable

Authentication Errors

  • Invalid credentials
  • Account locked
  • Token expired

Display Errors

All errors are displayed in a user-friendly format in the UI with appropriate styling.

Security Considerations

Implemented

  • Tokens stored in secure storage (encrypted)
  • Password field obscured
  • Auth token added to API headers automatically
  • Token cleared on logout
  • No sensitive data logged

Best Practices

  • Never log passwords or tokens
  • Use HTTPS for all API calls
  • Implement token refresh before expiration
  • Clear sensitive data on logout
  • Validate all user input

Dependencies

Core Dependencies

  • flutter_riverpod - State management
  • dartz - Functional programming (Either type)
  • flutter_secure_storage - Secure token storage
  • dio - HTTP client (via ApiClient)
  • equatable - Value equality
  • go_router - Navigation

Internal Dependencies

  • core/network/api_client.dart - HTTP client wrapper
  • core/storage/secure_storage.dart - Secure storage wrapper
  • core/errors/failures.dart - Error types
  • core/errors/exceptions.dart - Exception types
  • core/widgets/custom_button.dart - Button widget
  • core/widgets/loading_indicator.dart - Loading widget

Troubleshooting

Common Issues

Issue: Login always fails

  • Check API endpoint configuration in api_endpoints.dart
  • Verify API is running and accessible
  • Check network connectivity
  • Verify request/response format matches API

Issue: Tokens not persisted

  • Verify secure storage is initialized
  • Check device storage permissions
  • Clear app data and try again

Issue: Navigation doesn't work after login

  • Verify router configuration includes /warehouses route
  • Check if listener in LoginPage is properly set up
  • Ensure ProviderScope wraps the app

Issue: State not updating in UI

  • Ensure using ConsumerWidget or ConsumerStatefulWidget
  • Verify provider is being watched, not just read
  • Check if state is properly copied in copyWith

Future Enhancements

Planned Features

  1. Biometric Authentication

    • Face ID / Touch ID support
    • Fallback to password
  2. Token Auto-Refresh

    • Background token refresh
    • Seamless reauthentication
  3. Multi-factor Authentication

    • OTP support
    • SMS verification
  4. Remember Me

    • Optional persistent login
    • Secure device storage
  5. Password Reset

    • Email-based reset flow
    • Security questions

Contributing

When modifying this feature:

  1. Follow clean architecture principles
  2. Maintain separation of concerns (data/domain/presentation)
  3. Add tests for new functionality
  4. Update this README with changes
  5. Follow existing code style and patterns
  • App Router: lib/core/routing/app_router.dart
  • API Endpoints: lib/core/constants/api_endpoints.dart
  • App Theme: lib/core/theme/app_theme.dart
  • Main App: lib/main.dart