Skip to main content

rs_zero/rest/middleware/
auth.rs

1use axum::{
2    body::Body,
3    extract::Request,
4    http::header::AUTHORIZATION,
5    middleware::Next,
6    response::{IntoResponse, Response},
7};
8use jsonwebtoken::{Algorithm, DecodingKey, Validation, decode};
9use serde::Deserialize;
10
11use crate::rest::{AuthConfig, RestError};
12
13#[derive(Debug, Deserialize)]
14struct Claims {
15    exp: usize,
16}
17
18/// JWT bearer authorization middleware with exact-path public allowlist.
19pub async fn auth_middleware(auth: AuthConfig, request: Request<Body>, next: Next) -> Response {
20    if auth.is_public(request.uri().path()) {
21        return next.run(request).await;
22    }
23
24    let token = request
25        .headers()
26        .get(AUTHORIZATION)
27        .and_then(|value| value.to_str().ok())
28        .and_then(|value| value.strip_prefix("Bearer "))
29        .map(str::trim);
30
31    let Some(token) = token else {
32        return RestError::Unauthorized.into_response();
33    };
34
35    let mut validation = Validation::new(Algorithm::HS256);
36    validation.validate_exp = true;
37
38    match decode::<Claims>(
39        token,
40        &DecodingKey::from_secret(auth.secret.as_bytes()),
41        &validation,
42    ) {
43        Ok(data) => {
44            let _ = data.claims.exp;
45            next.run(request).await
46        }
47        Err(_) => RestError::Unauthorized.into_response(),
48    }
49}