289 lines
9.2 KiB
Markdown
289 lines
9.2 KiB
Markdown
|
|
# Authentication Error Handling with Internationalization
|
||
|
|
|
||
|
|
This document describes the enhanced authentication error handling system that provides localized error messages based on the current language setting.
|
||
|
|
|
||
|
|
## Overview
|
||
|
|
|
||
|
|
The authentication context has been updated to handle error messages in multiple languages, providing a better user experience for international users. The system includes:
|
||
|
|
|
||
|
|
1. **Comprehensive Error Mapping**: Server errors are mapped to appropriate translation keys
|
||
|
|
2. **Internationalized Error Messages**: All error messages are displayed in the user's current language
|
||
|
|
3. **Consistent Error Handling**: Standardized error handling across all authentication operations
|
||
|
|
4. **Reusable Components**: Pre-built components for displaying errors in different formats
|
||
|
|
|
||
|
|
## Features
|
||
|
|
|
||
|
|
### 1. Automatic Error Translation
|
||
|
|
|
||
|
|
The system automatically translates server error responses into the user's current language:
|
||
|
|
|
||
|
|
```rust
|
||
|
|
// Before (hardcoded English)
|
||
|
|
s.error = Some("Login failed".to_string());
|
||
|
|
|
||
|
|
// After (internationalized)
|
||
|
|
s.error = Some(error_handler.handle_request_failure("login"));
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Smart Error Mapping
|
||
|
|
|
||
|
|
Server responses are intelligently mapped to appropriate translation keys:
|
||
|
|
|
||
|
|
- JSON API responses are parsed and mapped
|
||
|
|
- Common error patterns are recognized
|
||
|
|
- Fallback to generic error messages when specific mapping isn't available
|
||
|
|
|
||
|
|
### 3. Comprehensive Error Coverage
|
||
|
|
|
||
|
|
The system handles all types of authentication errors:
|
||
|
|
|
||
|
|
- **Invalid Credentials**: Wrong username/password
|
||
|
|
- **Token Errors**: Expired or invalid tokens
|
||
|
|
- **Account Issues**: Suspended or unverified accounts
|
||
|
|
- **Network Errors**: Connection problems
|
||
|
|
- **Server Errors**: Internal server errors
|
||
|
|
- **Validation Errors**: Input validation failures
|
||
|
|
|
||
|
|
## Available Error Messages
|
||
|
|
|
||
|
|
### English (en.ftl)
|
||
|
|
```
|
||
|
|
invalid-credentials = Invalid email or password
|
||
|
|
user-not-found = User not found
|
||
|
|
email-already-exists = An account with this email already exists
|
||
|
|
username-already-exists = This username is already taken
|
||
|
|
invalid-token = Invalid authentication token
|
||
|
|
token-expired = Your authentication token has expired
|
||
|
|
insufficient-permissions = You don't have permission to perform this action
|
||
|
|
account-not-verified = Please verify your email before signing in
|
||
|
|
account-suspended = Your account has been suspended
|
||
|
|
rate-limit-exceeded = Too many attempts. Please try again later
|
||
|
|
oauth-error = OAuth authentication error
|
||
|
|
database-error = A database error occurred. Please try again
|
||
|
|
internal-error = An internal error occurred. Please try again
|
||
|
|
validation-error = Please check your input and try again
|
||
|
|
network-error = Network error. Please check your connection
|
||
|
|
login-failed = Login failed
|
||
|
|
registration-failed = Registration failed
|
||
|
|
session-expired = Your session has expired. Please sign in again
|
||
|
|
profile-update-failed = Failed to update profile
|
||
|
|
password-change-failed = Failed to change password
|
||
|
|
server-error = Server error occurred. Please try again later
|
||
|
|
request-failed = Request failed. Please try again
|
||
|
|
unknown-error = An unknown error occurred
|
||
|
|
```
|
||
|
|
|
||
|
|
### Spanish (es.ftl)
|
||
|
|
```
|
||
|
|
invalid-credentials = Correo electrónico o contraseña inválidos
|
||
|
|
user-not-found = Usuario no encontrado
|
||
|
|
email-already-exists = Ya existe una cuenta con este correo electrónico
|
||
|
|
username-already-exists = Este nombre de usuario ya está en uso
|
||
|
|
invalid-token = Token de autenticación inválido
|
||
|
|
token-expired = Tu token de autenticación ha expirado
|
||
|
|
insufficient-permissions = No tienes permisos para realizar esta acción
|
||
|
|
account-not-verified = Por favor verifica tu correo electrónico antes de iniciar sesión
|
||
|
|
account-suspended = Tu cuenta ha sido suspendida
|
||
|
|
rate-limit-exceeded = Demasiados intentos. Por favor intenta de nuevo más tarde
|
||
|
|
oauth-error = Error de autenticación OAuth
|
||
|
|
database-error = Ocurrió un error en la base de datos. Por favor intenta de nuevo
|
||
|
|
internal-error = Ocurrió un error interno. Por favor intenta de nuevo
|
||
|
|
validation-error = Por favor revisa tu información e intenta de nuevo
|
||
|
|
network-error = Error de red. Por favor verifica tu conexión
|
||
|
|
login-failed = Error al iniciar sesión
|
||
|
|
registration-failed = Error en el registro
|
||
|
|
session-expired = Tu sesión ha expirado. Por favor inicia sesión de nuevo
|
||
|
|
profile-update-failed = Error al actualizar el perfil
|
||
|
|
password-change-failed = Error al cambiar la contraseña
|
||
|
|
server-error = Error del servidor. Por favor intenta más tarde
|
||
|
|
request-failed = La solicitud falló. Por favor intenta de nuevo
|
||
|
|
unknown-error = Ocurrió un error desconocido
|
||
|
|
```
|
||
|
|
|
||
|
|
## Usage
|
||
|
|
|
||
|
|
### 1. Basic Error Handling
|
||
|
|
|
||
|
|
The authentication context automatically handles errors with localization:
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use crate::auth::use_auth;
|
||
|
|
|
||
|
|
#[component]
|
||
|
|
pub fn LoginComponent() -> impl IntoView {
|
||
|
|
let auth = use_auth();
|
||
|
|
|
||
|
|
view! {
|
||
|
|
<div>
|
||
|
|
// Error will be displayed in the current language
|
||
|
|
<Show when=move || auth.error().is_some()>
|
||
|
|
<div class="error">
|
||
|
|
{move || auth.error().unwrap_or_default()}
|
||
|
|
</div>
|
||
|
|
</Show>
|
||
|
|
</div>
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Using Error Display Components
|
||
|
|
|
||
|
|
Pre-built components are available for common error display patterns:
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use crate::auth::{AuthErrorDisplay, AuthErrorToast, InlineAuthError};
|
||
|
|
|
||
|
|
#[component]
|
||
|
|
pub fn MyComponent() -> impl IntoView {
|
||
|
|
let auth = use_auth();
|
||
|
|
|
||
|
|
view! {
|
||
|
|
<div>
|
||
|
|
// Alert-style error display
|
||
|
|
<AuthErrorDisplay
|
||
|
|
error=move || auth.error()
|
||
|
|
on_dismiss=Callback::new(move |_| {
|
||
|
|
auth.actions.clear_error();
|
||
|
|
})
|
||
|
|
/>
|
||
|
|
|
||
|
|
// Toast notification
|
||
|
|
<Show when=move || auth.error().is_some()>
|
||
|
|
<AuthErrorToast
|
||
|
|
error=move || auth.error().unwrap_or_default()
|
||
|
|
duration=5000
|
||
|
|
/>
|
||
|
|
</Show>
|
||
|
|
|
||
|
|
// Inline error display
|
||
|
|
<Show when=move || auth.error().is_some()>
|
||
|
|
<InlineAuthError
|
||
|
|
error=move || auth.error().unwrap_or_default()
|
||
|
|
/>
|
||
|
|
</Show>
|
||
|
|
</div>
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. Custom Error Handling
|
||
|
|
|
||
|
|
You can use the error handling utilities directly:
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use crate::auth::errors::{AuthErrorHandler, AuthErrorHandling};
|
||
|
|
use crate::i18n::use_i18n;
|
||
|
|
|
||
|
|
#[component]
|
||
|
|
pub fn CustomErrorHandling() -> impl IntoView {
|
||
|
|
let i18n = use_i18n();
|
||
|
|
let error_handler = AuthErrorHandler::new(i18n.clone());
|
||
|
|
|
||
|
|
// Handle a specific error
|
||
|
|
let error_message = error_handler.handle_request_failure("login");
|
||
|
|
|
||
|
|
// Or use the trait extension
|
||
|
|
let network_error = i18n.handle_network_error();
|
||
|
|
|
||
|
|
view! {
|
||
|
|
<div>
|
||
|
|
<p>{error_message}</p>
|
||
|
|
<p>{network_error}</p>
|
||
|
|
</div>
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Error Display Components
|
||
|
|
|
||
|
|
### AuthErrorDisplay
|
||
|
|
A full-featured error display component with dismiss functionality:
|
||
|
|
|
||
|
|
- Shows error with icon and styling
|
||
|
|
- Optional dismiss button
|
||
|
|
- Customizable CSS classes
|
||
|
|
- Callback when dismissed
|
||
|
|
|
||
|
|
### AuthErrorToast
|
||
|
|
A toast notification for non-blocking error display:
|
||
|
|
|
||
|
|
- Auto-dismisses after specified duration
|
||
|
|
- Positioned fixed in top-right corner
|
||
|
|
- Manual dismiss option
|
||
|
|
- Smooth animations
|
||
|
|
|
||
|
|
### InlineAuthError
|
||
|
|
A compact error display for inline use:
|
||
|
|
|
||
|
|
- Minimal styling
|
||
|
|
- Icon with text
|
||
|
|
- Suitable for form validation errors
|
||
|
|
|
||
|
|
## Implementation Details
|
||
|
|
|
||
|
|
### Error Mapping Logic
|
||
|
|
|
||
|
|
The `AuthErrorHandler` processes server errors in the following order:
|
||
|
|
|
||
|
|
1. **JSON Parsing**: Attempts to parse response as JSON and extract error messages
|
||
|
|
2. **Pattern Matching**: Matches error text against known patterns
|
||
|
|
3. **Fallback**: Uses generic error message if no specific match found
|
||
|
|
|
||
|
|
### Session Management
|
||
|
|
|
||
|
|
The system automatically handles session expiration:
|
||
|
|
|
||
|
|
- Detects expired tokens
|
||
|
|
- Clears user session
|
||
|
|
- Shows appropriate localized message
|
||
|
|
- Redirects to login when necessary
|
||
|
|
|
||
|
|
### Network Error Handling
|
||
|
|
|
||
|
|
Network errors are consistently handled across all operations:
|
||
|
|
|
||
|
|
- Connection timeouts
|
||
|
|
- Network unavailability
|
||
|
|
- Server unreachable
|
||
|
|
- DNS resolution failures
|
||
|
|
|
||
|
|
## Best Practices
|
||
|
|
|
||
|
|
1. **Always Clear Errors**: Use `auth.actions.clear_error()` when appropriate
|
||
|
|
2. **Provide User Feedback**: Show loading states during operations
|
||
|
|
3. **Handle Edge Cases**: Plan for unexpected error scenarios
|
||
|
|
4. **Test Multiple Languages**: Verify translations work correctly
|
||
|
|
5. **Use Appropriate Display**: Choose the right error display component for your use case
|
||
|
|
|
||
|
|
## Adding New Error Messages
|
||
|
|
|
||
|
|
To add new error messages:
|
||
|
|
|
||
|
|
1. Add the translation key to both `en.ftl` and `es.ftl`
|
||
|
|
2. Update the error mapping logic in `AuthErrorHandler`
|
||
|
|
3. Handle the new error type in your components
|
||
|
|
|
||
|
|
Example:
|
||
|
|
```rust
|
||
|
|
// In errors.rs
|
||
|
|
msg if msg.contains("two-factor required") => "two-factor-required".to_string(),
|
||
|
|
```
|
||
|
|
|
||
|
|
```
|
||
|
|
# In en.ftl
|
||
|
|
two-factor-required = Two-factor authentication is required
|
||
|
|
|
||
|
|
# In es.ftl
|
||
|
|
two-factor-required = Se requiere autenticación de dos factores
|
||
|
|
```
|
||
|
|
|
||
|
|
## Migration from Previous Version
|
||
|
|
|
||
|
|
If you're upgrading from a previous version:
|
||
|
|
|
||
|
|
1. Replace hardcoded error messages with translation keys
|
||
|
|
2. Update error handling in components to use new utilities
|
||
|
|
3. Test with different language settings
|
||
|
|
4. Update any custom error handling logic
|
||
|
|
|
||
|
|
The new system is backward compatible, but you'll need to update your components to take advantage of the internationalization features.
|