use axum::{ extract::FromRequestParts, http::request::Parts, }; use jsonwebtoken::{decode, DecodingKey, Validation}; use serde::{Deserialize, Serialize}; use uuid::Uuid; use crate::errors::AppError; #[derive(Debug, Serialize, Deserialize)] pub struct Claims { pub sub: Uuid, pub role: String, pub exp: u64, } #[derive(Debug, Clone)] pub struct AuthUser { pub id: Uuid, pub role: String, } impl FromRequestParts for AuthUser where S: Send + Sync, { type Rejection = AppError; async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result { // Retrieve Auth header let auth_header = parts .headers .get("Authorization") .and_then(|h| h.to_str().ok()) .ok_or_else(|| AppError::Unauthorized("Missing Authorization header".to_string()))?; if !auth_header.starts_with("Bearer ") { return Err(AppError::Unauthorized("Invalid Authorization header format".to_string())); } let token = &auth_header[7..]; // Decode JWT let jwt_secret = std::env::var("JWT_SECRET") .unwrap_or_else(|_| "invesa_secret_super_key_12345_secure_key".to_string()); let token_data = decode::( token, &DecodingKey::from_secret(jwt_secret.as_bytes()), &Validation::default(), ) .map_err(|err| AppError::Unauthorized(format!("Invalid token: {}", err)))?; Ok(AuthUser { id: token_data.claims.sub, role: token_data.claims.role, }) } }