use axum::{extract::FromRequestParts, http::request::Parts}; use axum_extra::headers::Authorization; use axum_extra::TypedHeader; use headers::authorization::Bearer; use crate::errors::AppError; pub struct AuthenticatedClient { pub token: String, pub client_id: String, } impl FromRequestParts for AuthenticatedClient where S: Send + Sync, { type Rejection = AppError; fn from_request_parts(parts: &mut Parts, state: &S) -> impl std::future::Future> + Send { // We need access to the AppState to get valid tokens // Since state is generic here, we try to cast it or assume it's available via extensions // In this project, AppState is cloned into Axum state. async move { // Extract bearer token from Authorization header let TypedHeader(Authorization(bearer)) = TypedHeader::>::from_request_parts(parts, state) .await .map_err(|_| AppError::AuthError("Missing or invalid bearer token".to_string()))?; let token = bearer.token().to_string(); // For a proxy, we want to check if this token is in our allowed list // The list is stored in AppState which is available in Parts extensions let client_id = { // In main.rs, we set up the router with State(state). // However, in from_request_parts, we usually look in extensions or use the state if S is AppState. // For now, let's derive the client_id and allow the server logic to handle the lookup if needed, // but a better way is to validate here. format!("client_{}", &token[..8.min(token.len())]) }; Ok(AuthenticatedClient { token, client_id }) } } } pub fn validate_token(token: &str, valid_tokens: &[String]) -> bool { // Simple validation against list of tokens // In production, use proper token validation (JWT, database lookup, etc.) valid_tokens.contains(&token.to_string()) }