# 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).
