openserve 2.0.3

A modern, high-performance, AI-enhanced file server built in Rust
Documentation
//! Authentication middleware

use axum::{
    extract::{Request, State},
    http::{StatusCode, HeaderMap},
    middleware::Next,
    response::Response,
};
use jsonwebtoken::{decode, DecodingKey, Validation};
use serde::{Deserialize, Serialize};
use tracing::{debug, warn};

use crate::server::AppState;

/// Represents the claims in a JSON Web Token (JWT).
#[derive(Debug, Serialize, Deserialize)]
pub struct Claims {
    /// The subject of the token (usually the user ID).
    pub sub: String,
    /// The expiration time of the token.
    pub exp: usize,
    /// The time the token was issued at.
    pub iat: usize,
    /// The role of the user.
    pub role: String,
}

/// Authentication middleware
pub async fn auth_middleware(
    State(state): State<AppState>,
    headers: HeaderMap,
    request: Request,
    next: Next,
) -> Result<Response, StatusCode> {
    // Skip auth for health check and metrics
    let path = request.uri().path();
    if path == "/health" || path == "/metrics" || !state.config.auth.enabled {
        return Ok(next.run(request).await);
    }

    // Extract authorization header
    let auth_header = headers
        .get("Authorization")
        .and_then(|header| header.to_str().ok())
        .and_then(|header| header.strip_prefix("Bearer "));

    let token = match auth_header {
        Some(token) => token,
        None => {
            warn!("Missing authorization header");
            return Err(StatusCode::UNAUTHORIZED);
        }
    };

    // Validate JWT token
    let decoding_key = DecodingKey::from_secret(state.config.auth.jwt_secret.as_bytes());
    let validation = Validation::default();

    match decode::<Claims>(token, &decoding_key, &validation) {
        Ok(token_data) => {
            debug!("Authenticated user: {}", token_data.claims.sub);
            // You could add user info to request extensions here
            Ok(next.run(request).await)
        }
        Err(e) => {
            warn!("Invalid token: {}", e);
            Err(StatusCode::UNAUTHORIZED)
        }
    }
}