#![allow(dead_code)] #![allow(unused_imports)] use crate::auth::jwt::Claims; use crate::config::AppState; use axum::{ extract::{Request, State}, http::StatusCode, middleware::Next, response::Response, }; use mongodb::bson::oid::ObjectId; pub async fn jwt_auth_middleware( State(state): State, mut req: Request, next: Next, ) -> Result { let headers = req.headers(); // Extract Authorization header let auth_header = headers .get("Authorization") .and_then(|h| h.to_str().ok()) .ok_or(StatusCode::UNAUTHORIZED)?; // Check Bearer token format if !auth_header.starts_with("Bearer ") { return Err(StatusCode::UNAUTHORIZED); } let token = &auth_header[7..]; // Remove "Bearer " prefix // Verify signature and expiry. let claims = state .jwt_service .validate_token(token) .map_err(|_| StatusCode::UNAUTHORIZED)?; // Reject tokens whose version is stale (e.g. issued before a password // change). The user's current version is cached briefly so we don't hit // Mongo on every request; a missing user (deleted) also means 401. let user_oid = ObjectId::parse_str(&claims.sub).map_err(|_| StatusCode::UNAUTHORIZED)?; let current_version = state .token_version_cache .get_or_load(&user_oid, &state.db) .await .map_err(|_| StatusCode::UNAUTHORIZED)?; match current_version { Some(v) if v == claims.token_version => {} _ => return Err(StatusCode::UNAUTHORIZED), } // Add claims to request extensions for handlers to use req.extensions_mut().insert(claims); Ok(next.run(req).await) } // Extension method to extract claims from request pub trait RequestClaimsExt { fn claims(&self) -> Option<&Claims>; } impl RequestClaimsExt for Request { fn claims(&self) -> Option<&Claims> { self.extensions().get::() } }