# lmrc-auth
Authentication framework for LMRC Stack applications.
Provides flexible, trait-based authentication with multiple providers, session management, and ready-to-use Axum handlers.
## Features
- **Flexible Authentication**: Trait-based design supports database, LDAP, OAuth, and custom providers
- **Session Management**: Secure session creation, validation, and destruction
- **Password Hashing**: Built-in bcrypt support for secure password storage
- **Database Integration**: SeaORM-based provider for PostgreSQL authentication
- **Axum Ready**: Pre-built handlers and middleware for Axum web framework
- **Type-Safe**: Leverages Rust's type system for security
## Installation
```toml
[dependencies]
lmrc-auth = "0.3.11"
```
### Feature Flags
- `bcrypt` (default) - Password hashing with bcrypt
- `database` - Database-backed authentication provider with SeaORM
To enable all features:
```toml
[dependencies]
lmrc-auth = { version = "0.3.11", features = ["database"] }
```
## Quick Start
### 1. Database Setup
Create the required tables:
```sql
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
role VARCHAR(50) NOT NULL DEFAULT 'user',
is_active BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE TABLE sessions (
token VARCHAR(255) PRIMARY KEY,
user_id BIGINT NOT NULL REFERENCES users(id),
expires_at TIMESTAMP NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW()
);
```
### 2. Configure Authentication
```rust
use lmrc_auth::{DatabaseAuthProvider, AuthConfig};
use sea_orm::Database;
use std::sync::Arc;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Connect to database
let db = Database::connect("postgres://user:pass@localhost/mydb").await?;
// Create auth provider
let auth_provider = Arc::new(
DatabaseAuthProvider::new(
db,
"users", // users table name
"sessions", // sessions table name
AuthConfig::default()
)
);
// Use in your Axum application
Ok(())
}
```
### 3. Add Authentication Routes
```rust
use axum::{Router, routing::post};
use lmrc_auth::handlers::{login_handler, logout_handler, me_handler};
let auth_routes = Router::new()
.route("/auth/login", post(login_handler))
.route("/auth/logout", post(logout_handler))
.route("/auth/me", get(me_handler))
.with_state((auth_provider.clone(), auth_config));
```
### 4. Protect Routes with Middleware
```rust
use axum::middleware;
use lmrc_auth::middleware::auth_middleware;
let protected_routes = Router::new()
.route("/admin/users", get(list_users))
.route("/admin/settings", get(get_settings))
.layer(middleware::from_fn_with_state(
(auth_provider, auth_config),
auth_middleware
));
```
## Core Concepts
### AuthProvider Trait
The `AuthProvider` trait defines the authentication interface:
```rust
#[async_trait]
pub trait AuthProvider: Send + Sync {
async fn authenticate(&self, email: &str, password: &str) -> AuthResult<AuthUser>;
async fn create_session(&self, user_id: i64) -> AuthResult<Session>;
async fn validate_session(&self, token: &str) -> AuthResult<Option<AuthUser>>;
async fn destroy_session(&self, token: &str) -> AuthResult<()>;
async fn get_user(&self, user_id: i64) -> AuthResult<Option<AuthUser>>;
}
```
### Custom Providers
Implement custom authentication strategies:
```rust
use lmrc_auth::{AuthProvider, AuthUser, Session, AuthResult};
use async_trait::async_trait;
struct LdapAuthProvider {
ldap_url: String,
}
#[async_trait]
impl AuthProvider for LdapAuthProvider {
async fn authenticate(&self, email: &str, password: &str) -> AuthResult<AuthUser> {
// Your LDAP authentication logic
todo!()
}
// Implement other methods...
}
```
### Data Models
#### AuthUser
```rust
pub struct AuthUser {
pub id: i64,
pub email: String,
pub role: String,
}
```
#### Session
```rust
pub struct Session {
pub token: String,
pub user_id: i64,
pub expires_at: chrono::NaiveDateTime,
}
```
#### Credentials
```rust
pub struct Credentials {
pub email: String,
pub password: String,
}
```
## Configuration
### AuthConfig
```rust
pub struct AuthConfig {
/// Session expiration in hours (default: 168 / 7 days)
pub session_expiration_hours: i64,
/// Cookie name for session token (default: "session_token")
pub cookie_name: String,
/// Cookie domain (default: None)
pub cookie_domain: Option<String>,
/// Cookie secure flag - HTTPS only (default: true)
pub cookie_secure: bool,
}
```
### Custom Configuration
```rust
let config = AuthConfig {
session_expiration_hours: 24, // 1 day
cookie_name: "my_session".to_string(),
cookie_domain: Some(".example.com".to_string()),
cookie_secure: true,
};
```
## Examples
### Login Handler
```rust
use axum::{Json, extract::State};
use lmrc_auth::{handlers::login_handler, Credentials, LoginResponse};
// POST /auth/login
// Body: {"email": "user@example.com", "password": "secret"}
// Returns: {"token": "...", "user": {...}, "expires_at": "..."}
```
### Logout Handler
```rust
// POST /auth/logout
// Cookie: session_token=...
// Returns: 204 No Content
```
### Get Current User
```rust
// GET /auth/me
// Cookie: session_token=...
// Returns: {"id": 1, "email": "user@example.com", "role": "admin"}
```
## Testing
```bash
cargo test -p lmrc-auth --all-features
```
## Security Considerations
1. **Password Hashing**: Uses bcrypt with appropriate cost factor
2. **Session Tokens**: Generated using UUID v4 (cryptographically random)
3. **Session Expiration**: Configurable expiration with automatic cleanup
4. **Secure Cookies**: HTTPS-only cookies by default
5. **SQL Injection**: Uses parameterized queries via SeaORM
## Integration with lmrc-http-common
Works seamlessly with [lmrc-http-common](../lmrc-http-common) for error handling, middleware, and HTTP utilities.
## Contributing
This library is part of the [LMRC Stack](https://gitlab.com/lemarco/lmrc-stack) monorepo.
## License
Dual licensed under MIT OR Apache-2.0 (your choice).