mockforge_collab/
middleware.rs

1//! Middleware for authentication and authorization
2
3use crate::auth::AuthService;
4use crate::error::CollabError;
5use axum::{
6    extract::{Request, State},
7    http::StatusCode,
8    middleware::Next,
9    response::Response,
10};
11use std::sync::Arc;
12use uuid::Uuid;
13
14/// Extension for authenticated user
15#[derive(Clone, Debug)]
16pub struct AuthUser {
17    pub user_id: Uuid,
18    pub username: String,
19}
20
21/// JWT authentication middleware
22pub async fn auth_middleware(
23    State(auth): State<Arc<AuthService>>,
24    mut request: Request,
25    next: Next,
26) -> Result<Response, (StatusCode, String)> {
27    // Extract Authorization header
28    let auth_header = request
29        .headers()
30        .get("Authorization")
31        .and_then(|h| h.to_str().ok())
32        .ok_or_else(|| (StatusCode::UNAUTHORIZED, "Missing Authorization header".to_string()))?;
33
34    // Check Bearer prefix
35    let token = auth_header.strip_prefix("Bearer ").ok_or_else(|| {
36        (StatusCode::UNAUTHORIZED, "Invalid Authorization header format".to_string())
37    })?;
38
39    // Verify token
40    let claims = auth
41        .verify_token(token)
42        .map_err(|e| (StatusCode::UNAUTHORIZED, format!("Invalid token: {}", e)))?;
43
44    // Parse user ID
45    let user_id = Uuid::parse_str(&claims.sub)
46        .map_err(|_| (StatusCode::INTERNAL_SERVER_ERROR, "Invalid user ID in token".to_string()))?;
47
48    // Add user to request extensions
49    request.extensions_mut().insert(AuthUser {
50        user_id,
51        username: claims.username,
52    });
53
54    Ok(next.run(request).await)
55}
56
57/// Extract authenticated user from request
58pub fn extract_auth_user(request: &Request) -> Result<&AuthUser, CollabError> {
59    request
60        .extensions()
61        .get::<AuthUser>()
62        .ok_or_else(|| CollabError::AuthenticationFailed("Not authenticated".to_string()))
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn test_auth_user_creation() {
71        let user = AuthUser {
72            user_id: Uuid::new_v4(),
73            username: "testuser".to_string(),
74        };
75
76        assert_eq!(user.username, "testuser");
77    }
78}