446 lines
13 KiB
Markdown
446 lines
13 KiB
Markdown
|
|
# Authentication & Authorization System
|
||
|
|
|
||
|
|
A comprehensive authentication and authorization system built with Rust, featuring JWT tokens, OAuth2 integration, role-based access control (RBAC), and secure session management.
|
||
|
|
|
||
|
|
## 🚀 Features
|
||
|
|
|
||
|
|
### Core Authentication
|
||
|
|
- **JWT Token Authentication** - Secure token-based authentication with access and refresh tokens
|
||
|
|
- **Password-based Authentication** - Secure password hashing using Argon2
|
||
|
|
- **Session Management** - Secure session handling with HTTP-only cookies
|
||
|
|
- **Password Reset** - Secure password reset flow with time-limited tokens
|
||
|
|
|
||
|
|
### OAuth2 Integration
|
||
|
|
- **Google OAuth** - Sign in with Google accounts
|
||
|
|
- **GitHub OAuth** - Sign in with GitHub accounts
|
||
|
|
- **Discord OAuth** - Sign in with Discord accounts
|
||
|
|
- **Microsoft OAuth** - Sign in with Microsoft accounts
|
||
|
|
- **Extensible** - Easy to add custom OAuth providers
|
||
|
|
|
||
|
|
### Authorization (RBAC)
|
||
|
|
- **Role-Based Access Control** - Flexible role system with built-in roles
|
||
|
|
- **Fine-grained Permissions** - Permission-based access control
|
||
|
|
- **Custom Roles** - Support for custom role definitions
|
||
|
|
- **Middleware Protection** - Route-level authorization middleware
|
||
|
|
|
||
|
|
### Security Features
|
||
|
|
- **CSRF Protection** - Built-in CSRF token validation
|
||
|
|
- **Rate Limiting** - Configurable rate limiting for auth endpoints
|
||
|
|
- **Security Headers** - Comprehensive security headers
|
||
|
|
- **Password Strength** - Configurable password complexity requirements
|
||
|
|
- **Token Blacklisting** - Ability to invalidate tokens
|
||
|
|
- **Audit Logging** - Complete audit trail for user actions
|
||
|
|
|
||
|
|
## 📋 Architecture
|
||
|
|
|
||
|
|
### Backend Components
|
||
|
|
- **`auth/service.rs`** - Main authentication service
|
||
|
|
- **`auth/jwt.rs`** - JWT token management
|
||
|
|
- **`auth/oauth.rs`** - OAuth2 provider integration
|
||
|
|
- **`auth/password.rs`** - Password hashing and validation
|
||
|
|
- **`auth/repository.rs`** - Database operations
|
||
|
|
- **`auth/middleware.rs`** - Authentication middleware
|
||
|
|
- **`auth/routes.rs`** - HTTP API endpoints
|
||
|
|
|
||
|
|
### Frontend Components
|
||
|
|
- **`auth/context.rs`** - React-style auth context
|
||
|
|
- **`auth/login.rs`** - Login form component
|
||
|
|
- **Auth Guards** - Route protection components
|
||
|
|
|
||
|
|
### Database Schema
|
||
|
|
- **`users`** - User accounts and profiles
|
||
|
|
- **`user_roles`** - Role assignments
|
||
|
|
- **`oauth_accounts`** - OAuth provider links
|
||
|
|
- **`sessions`** - Session management
|
||
|
|
- **`tokens`** - Security tokens
|
||
|
|
- **`permissions`** - System permissions
|
||
|
|
- **`role_permissions`** - Role-permission mappings
|
||
|
|
- **`user_audit_log`** - Audit trail
|
||
|
|
|
||
|
|
## 🔧 Installation & Setup
|
||
|
|
|
||
|
|
### 1. Database Setup
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Create PostgreSQL database
|
||
|
|
createdb rustelo_dev
|
||
|
|
|
||
|
|
# Run migrations
|
||
|
|
psql rustelo_dev < migrations/001_create_auth_tables.sql
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Environment Configuration
|
||
|
|
|
||
|
|
Create a `.env` file with the following variables:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Database
|
||
|
|
DATABASE_URL=postgres://username:password@localhost:5432/rustelo_dev
|
||
|
|
|
||
|
|
# JWT Configuration
|
||
|
|
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production
|
||
|
|
JWT_ISSUER=rustelo-auth
|
||
|
|
JWT_ACCESS_TOKEN_EXPIRES_IN=15 # minutes
|
||
|
|
JWT_REFRESH_TOKEN_EXPIRES_IN=7 # days
|
||
|
|
|
||
|
|
# Password Security
|
||
|
|
# Argon2 uses secure defaults, no configuration needed
|
||
|
|
|
||
|
|
# OAuth Configuration (optional)
|
||
|
|
OAUTH_REDIRECT_BASE_URL=http://localhost:3030/api/auth/oauth/callback
|
||
|
|
|
||
|
|
# Google OAuth
|
||
|
|
GOOGLE_CLIENT_ID=your-google-client-id
|
||
|
|
GOOGLE_CLIENT_SECRET=your-google-client-secret
|
||
|
|
|
||
|
|
# GitHub OAuth
|
||
|
|
GITHUB_CLIENT_ID=your-github-client-id
|
||
|
|
GITHUB_CLIENT_SECRET=your-github-client-secret
|
||
|
|
|
||
|
|
# Discord OAuth
|
||
|
|
DISCORD_CLIENT_ID=your-discord-client-id
|
||
|
|
DISCORD_CLIENT_SECRET=your-discord-client-secret
|
||
|
|
|
||
|
|
# Microsoft OAuth
|
||
|
|
MICROSOFT_CLIENT_ID=your-microsoft-client-id
|
||
|
|
MICROSOFT_CLIENT_SECRET=your-microsoft-client-secret
|
||
|
|
MICROSOFT_TENANT_ID=common
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. Dependencies
|
||
|
|
|
||
|
|
The system automatically includes all necessary dependencies. Key dependencies include:
|
||
|
|
- `jsonwebtoken` - JWT token handling
|
||
|
|
- `argon2` - Password hashing
|
||
|
|
- `oauth2` - OAuth2 client implementation
|
||
|
|
- `sqlx` - Database operations
|
||
|
|
- `tower-cookies` - Cookie management
|
||
|
|
- `reqwest` - HTTP client for OAuth
|
||
|
|
|
||
|
|
## 🔐 Usage
|
||
|
|
|
||
|
|
### Backend Usage
|
||
|
|
|
||
|
|
#### Basic Authentication Service
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use auth::{AuthService, AuthRepository, JwtService, OAuthService, PasswordService};
|
||
|
|
use std::sync::Arc;
|
||
|
|
|
||
|
|
// Initialize services
|
||
|
|
let auth_repo = Arc::new(AuthRepository::new(pool));
|
||
|
|
let jwt_service = Arc::new(JwtService::new()?);
|
||
|
|
let oauth_service = Arc::new(OAuthService::new()?);
|
||
|
|
let password_service = Arc::new(PasswordService::new());
|
||
|
|
|
||
|
|
let auth_service = Arc::new(AuthService::new(
|
||
|
|
jwt_service,
|
||
|
|
oauth_service,
|
||
|
|
password_service,
|
||
|
|
auth_repo,
|
||
|
|
));
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Protecting Routes
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use auth::middleware::{require_auth, require_admin, require_permission};
|
||
|
|
use shared::auth::Permission;
|
||
|
|
|
||
|
|
// Require authentication
|
||
|
|
app.route("/protected", get(handler))
|
||
|
|
.layer(axum::middleware::from_fn(require_auth));
|
||
|
|
|
||
|
|
// Require admin role
|
||
|
|
app.route("/admin", get(admin_handler))
|
||
|
|
.layer(axum::middleware::from_fn(require_admin));
|
||
|
|
|
||
|
|
// Require specific permission
|
||
|
|
app.route("/users", get(users_handler))
|
||
|
|
.layer(axum::middleware::from_fn(require_permission(Permission::ReadUsers)));
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Custom Authorization
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use auth::middleware::{AuthContext, extract_user_from_request};
|
||
|
|
|
||
|
|
async fn protected_handler(request: Request) -> Result<Response, Error> {
|
||
|
|
let user = extract_user_from_request(&request)?;
|
||
|
|
|
||
|
|
if !user.has_permission(&Permission::WriteContent) {
|
||
|
|
return Err(AuthError::InsufficientPermissions.into());
|
||
|
|
}
|
||
|
|
|
||
|
|
// Handler logic here
|
||
|
|
Ok(Response::new("Success"))
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Frontend Usage
|
||
|
|
|
||
|
|
#### Authentication Context
|
||
|
|
|
||
|
|
```rust
|
||
|
|
use leptos::prelude::*;
|
||
|
|
use auth::{AuthProvider, use_auth};
|
||
|
|
|
||
|
|
#[component]
|
||
|
|
fn App() -> impl IntoView {
|
||
|
|
view! {
|
||
|
|
<AuthProvider>
|
||
|
|
<Router>
|
||
|
|
<Routes>
|
||
|
|
<Route path="/login" view=LoginPage />
|
||
|
|
<Route path="/dashboard" view=ProtectedPage />
|
||
|
|
</Routes>
|
||
|
|
</Router>
|
||
|
|
</AuthProvider>
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Using Authentication
|
||
|
|
|
||
|
|
```rust
|
||
|
|
#[component]
|
||
|
|
fn LoginPage() -> impl IntoView {
|
||
|
|
let auth = use_auth();
|
||
|
|
|
||
|
|
let login = move |email: String, password: String| {
|
||
|
|
(auth.0.actions.login)(email, password, false);
|
||
|
|
};
|
||
|
|
|
||
|
|
view! {
|
||
|
|
<div>
|
||
|
|
<Show when=move || auth.0.is_authenticated()>
|
||
|
|
<p>"Welcome, " {move || auth.0.user().map(|u| u.display_name_or_username().to_string()).unwrap_or_default()}</p>
|
||
|
|
</Show>
|
||
|
|
<LoginForm />
|
||
|
|
</div>
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Route Protection
|
||
|
|
|
||
|
|
```rust
|
||
|
|
#[component]
|
||
|
|
fn ProtectedPage() -> impl IntoView {
|
||
|
|
let auth = use_auth();
|
||
|
|
|
||
|
|
view! {
|
||
|
|
<Show
|
||
|
|
when=move || auth.0.is_authenticated()
|
||
|
|
fallback=move || view! { <Redirect path="/login" /> }
|
||
|
|
>
|
||
|
|
<div>"Protected content"</div>
|
||
|
|
</Show>
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 🛡️ Security Features
|
||
|
|
|
||
|
|
### Password Security
|
||
|
|
- **Argon2 Hashing** - State-of-the-art password hashing algorithm
|
||
|
|
- **Secure Defaults** - Uses recommended Argon2id variant with secure parameters
|
||
|
|
- **Strength Validation** - Enforced password complexity
|
||
|
|
- **Common Password Detection** - Prevents weak passwords
|
||
|
|
|
||
|
|
### Token Security
|
||
|
|
- **JWT with HS256** - Secure token signing
|
||
|
|
- **Short-lived Access Tokens** - Default 15-minute expiration
|
||
|
|
- **Refresh Token Rotation** - Secure token refresh
|
||
|
|
- **Token Blacklisting** - Ability to invalidate tokens
|
||
|
|
|
||
|
|
### Session Security
|
||
|
|
- **HTTP-Only Cookies** - Prevents XSS attacks
|
||
|
|
- **Secure Cookies** - HTTPS-only transmission
|
||
|
|
- **SameSite Protection** - CSRF prevention
|
||
|
|
- **Session Expiration** - Automatic cleanup
|
||
|
|
|
||
|
|
### OAuth Security
|
||
|
|
- **PKCE Support** - Proof Key for Code Exchange
|
||
|
|
- **State Parameter** - CSRF protection
|
||
|
|
- **Secure Redirects** - Validated redirect URLs
|
||
|
|
- **Token Validation** - Proper token verification
|
||
|
|
|
||
|
|
## 🔄 API Endpoints
|
||
|
|
|
||
|
|
### Authentication Endpoints
|
||
|
|
|
||
|
|
| Method | Endpoint | Description | Auth Required |
|
||
|
|
|--------|----------|-------------|---------------|
|
||
|
|
| POST | `/api/auth/register` | Register new user | No |
|
||
|
|
| POST | `/api/auth/login` | Login with credentials | No |
|
||
|
|
| POST | `/api/auth/logout` | Logout current user | Yes |
|
||
|
|
| POST | `/api/auth/refresh` | Refresh access token | No |
|
||
|
|
| GET | `/api/auth/profile` | Get user profile | Yes |
|
||
|
|
| PUT | `/api/auth/profile` | Update user profile | Yes |
|
||
|
|
| POST | `/api/auth/change-password` | Change password | Yes |
|
||
|
|
|
||
|
|
### OAuth Endpoints
|
||
|
|
|
||
|
|
| Method | Endpoint | Description | Auth Required |
|
||
|
|
|--------|----------|-------------|---------------|
|
||
|
|
| GET | `/api/auth/oauth/providers` | List OAuth providers | No |
|
||
|
|
| GET | `/api/auth/oauth/:provider/authorize` | Get OAuth URL | No |
|
||
|
|
| GET | `/api/auth/oauth/:provider/callback` | Handle OAuth callback | No |
|
||
|
|
|
||
|
|
### Password Reset Endpoints
|
||
|
|
|
||
|
|
| Method | Endpoint | Description | Auth Required |
|
||
|
|
|--------|----------|-------------|---------------|
|
||
|
|
| POST | `/api/auth/password-reset/request` | Request password reset | No |
|
||
|
|
| POST | `/api/auth/password-reset/confirm` | Confirm password reset | No |
|
||
|
|
|
||
|
|
### Admin Endpoints
|
||
|
|
|
||
|
|
| Method | Endpoint | Description | Auth Required |
|
||
|
|
|--------|----------|-------------|---------------|
|
||
|
|
| GET | `/api/auth/admin/users/:id` | Get user by ID | Admin |
|
||
|
|
| POST | `/api/auth/admin/users/:id/verify-email` | Verify user email | Admin |
|
||
|
|
| POST | `/api/auth/admin/cleanup` | Clean expired data | Admin |
|
||
|
|
|
||
|
|
## 🎯 Role-Based Access Control
|
||
|
|
|
||
|
|
### Default Roles
|
||
|
|
|
||
|
|
- **Admin** - Full system access
|
||
|
|
- **Moderator** - Content management
|
||
|
|
- **User** - Standard user access
|
||
|
|
- **Guest** - Read-only access
|
||
|
|
|
||
|
|
### Default Permissions
|
||
|
|
|
||
|
|
- **ReadUsers** - View user information
|
||
|
|
- **WriteUsers** - Create/update users
|
||
|
|
- **DeleteUsers** - Delete users
|
||
|
|
- **ReadContent** - View content
|
||
|
|
- **WriteContent** - Create/update content
|
||
|
|
- **DeleteContent** - Delete content
|
||
|
|
- **ManageRoles** - Manage user roles
|
||
|
|
- **ManageSystem** - System administration
|
||
|
|
|
||
|
|
### Custom Roles
|
||
|
|
|
||
|
|
```rust
|
||
|
|
// Add custom role
|
||
|
|
auth_service.repository.assign_role(user_id, Role::Custom("editor".to_string())).await?;
|
||
|
|
|
||
|
|
// Check custom role
|
||
|
|
if user.has_role(&Role::Custom("editor".to_string())) {
|
||
|
|
// Allow editor actions
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## 📊 Audit Logging
|
||
|
|
|
||
|
|
All authentication events are logged:
|
||
|
|
- User registration
|
||
|
|
- Login/logout events
|
||
|
|
- Password changes
|
||
|
|
- Profile updates
|
||
|
|
- Role changes
|
||
|
|
- OAuth authentications
|
||
|
|
|
||
|
|
Access logs via:
|
||
|
|
```sql
|
||
|
|
SELECT * FROM user_audit_log WHERE user_id = $1 ORDER BY created_at DESC;
|
||
|
|
```
|
||
|
|
|
||
|
|
## 🔧 Maintenance
|
||
|
|
|
||
|
|
### Cleanup Expired Data
|
||
|
|
|
||
|
|
```rust
|
||
|
|
// Manual cleanup
|
||
|
|
auth_service.cleanup_expired().await?;
|
||
|
|
|
||
|
|
// Or via SQL function
|
||
|
|
SELECT cleanup_expired_auth_data();
|
||
|
|
```
|
||
|
|
|
||
|
|
### Database Maintenance
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- Vacuum tables periodically
|
||
|
|
VACUUM ANALYZE users;
|
||
|
|
VACUUM ANALYZE sessions;
|
||
|
|
VACUUM ANALYZE tokens;
|
||
|
|
VACUUM ANALYZE user_audit_log;
|
||
|
|
```
|
||
|
|
|
||
|
|
## 🚨 Common Issues
|
||
|
|
|
||
|
|
### JWT Token Issues
|
||
|
|
- **Invalid Token** - Check JWT_SECRET consistency
|
||
|
|
- **Token Expired** - Implement refresh token logic
|
||
|
|
- **Clock Skew** - Ensure server time synchronization
|
||
|
|
|
||
|
|
### OAuth Issues
|
||
|
|
- **Callback Errors** - Verify redirect URLs match exactly
|
||
|
|
- **Provider Errors** - Check client ID/secret configuration
|
||
|
|
- **PKCE Failures** - Ensure PKCE verifier storage
|
||
|
|
|
||
|
|
### Database Issues
|
||
|
|
- **Connection Errors** - Verify DATABASE_URL
|
||
|
|
- **Migration Failures** - Check PostgreSQL version compatibility
|
||
|
|
- **Performance Issues** - Ensure proper indexing
|
||
|
|
|
||
|
|
## 📈 Performance Considerations
|
||
|
|
|
||
|
|
### Database Optimization
|
||
|
|
- **Indexes** - All critical queries are indexed
|
||
|
|
- **Connection Pooling** - SQLx connection pool
|
||
|
|
- **Query Optimization** - Efficient join queries
|
||
|
|
|
||
|
|
### Caching
|
||
|
|
- **JWT Verification** - Cache public keys
|
||
|
|
- **User Data** - Consider Redis for session storage
|
||
|
|
- **Rate Limiting** - In-memory or Redis-based
|
||
|
|
|
||
|
|
### Monitoring
|
||
|
|
- **Metrics** - Track authentication success/failure rates
|
||
|
|
- **Logging** - Comprehensive audit logging
|
||
|
|
- **Health Checks** - Database connection monitoring
|
||
|
|
|
||
|
|
## 🔮 Future Enhancements
|
||
|
|
|
||
|
|
### Planned Features
|
||
|
|
- **WebAuthn Support** - Passwordless authentication
|
||
|
|
- **Multi-Factor Authentication** - TOTP/SMS support
|
||
|
|
- **Social Login** - Additional OAuth providers
|
||
|
|
- **Advanced RBAC** - Hierarchical roles
|
||
|
|
- **API Keys** - Service-to-service authentication
|
||
|
|
|
||
|
|
### Integration Options
|
||
|
|
- **Email Service** - Password reset emails
|
||
|
|
- **SMS Service** - Two-factor authentication
|
||
|
|
- **Monitoring** - Prometheus metrics
|
||
|
|
- **Analytics** - User behavior tracking
|
||
|
|
|
||
|
|
## 🤝 Contributing
|
||
|
|
|
||
|
|
1. Fork the repository
|
||
|
|
2. Create a feature branch
|
||
|
|
3. Add comprehensive tests
|
||
|
|
4. Update documentation
|
||
|
|
5. Submit a pull request
|
||
|
|
|
||
|
|
## 📄 License
|
||
|
|
|
||
|
|
This authentication system is part of the Rustelo template and follows the same licensing terms.
|
||
|
|
|
||
|
|
## 🆘 Support
|
||
|
|
|
||
|
|
For questions and support:
|
||
|
|
- Check the [ENV_CONFIG.md](ENV_CONFIG.md) for configuration details
|
||
|
|
- Review the migration files for database schema
|
||
|
|
- Examine the test files for usage examples
|
||
|
|
- Open an issue for bugs or feature requests
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**Security Notice**: This system implements industry-standard security practices, but always review and customize security settings for your specific use case. Change default passwords and secrets before production deployment.
|