use axum::{ extract::FromRequestParts, http::{request::Parts, StatusCode}, }; use std::future::Future; pub struct RequireAuth(pub crate::jwt::Claims); impl FromRequestParts for RequireAuth where S: Send + Sync, { type Rejection = (StatusCode, &'static str); fn from_request_parts( parts: &mut Parts, _state: &S, ) -> impl Future> + Send { let token = parts .headers .get("Authorization") .and_then(|value| value.to_str().ok()) .filter(|value| value.starts_with("Bearer ")) .map(|header| header.trim_start_matches("Bearer ").to_string()); async move { let token = match token { Some(token) => token, None => return Err((StatusCode::UNAUTHORIZED, "Missing Bearer token")), }; let jwt_secret = std::env::var("JWT_SECRET").expect("JWT_SECRET must be set"); match crate::jwt::verify_access_token(&token, &jwt_secret) { Ok(claims) => Ok(RequireAuth(claims)), Err(_) => Err((StatusCode::UNAUTHORIZED, "Invalid or expired token")), } } } }