Skip to main content

meerkat_mobkit/
http_auth.rs

1//! HTTP middleware for Bearer token authentication using JWT/JWKS.
2
3use axum::Router;
4use axum::extract::Request;
5use axum::http::StatusCode;
6use axum::middleware::Next;
7use axum::response::Response;
8
9use crate::auth::JwksCache;
10
11/// Axum middleware that validates Bearer tokens using a [`JwksCache`].
12///
13/// On success the [`ValidatedJwt`] is inserted into request extensions so
14/// downstream handlers can extract it via `Extension<ValidatedJwt>`.
15///
16/// On failure the middleware short-circuits with `401 Unauthorized`.
17pub async fn auth_middleware(
18    axum::extract::State(cache): axum::extract::State<JwksCache>,
19    mut request: Request,
20    next: Next,
21) -> Result<Response, StatusCode> {
22    let token = extract_bearer_token(&request).ok_or(StatusCode::UNAUTHORIZED)?;
23
24    let validated_jwt = cache
25        .validate_token(token)
26        .await
27        .map_err(|_| StatusCode::UNAUTHORIZED)?;
28
29    request.extensions_mut().insert(validated_jwt);
30    Ok(next.run(request).await)
31}
32
33/// Wrap a router with Bearer-token authentication backed by a JWKS cache.
34pub fn with_auth_layer(router: Router, jwks_cache: JwksCache) -> Router {
35    router.layer(axum::middleware::from_fn_with_state(
36        jwks_cache,
37        auth_middleware,
38    ))
39}
40
41fn extract_bearer_token(request: &Request) -> Option<&str> {
42    let header_value = request
43        .headers()
44        .get(axum::http::header::AUTHORIZATION)?
45        .to_str()
46        .ok()?;
47    let token = header_value.strip_prefix("Bearer ")?;
48    if token.is_empty() {
49        return None;
50    }
51    Some(token)
52}