Skip to main content

salvor_server/
auth.rs

1//! Bearer-token auth, the whole of it.
2//!
3//! The posture is single-tenant: either a shared secret
4//! guards every endpoint, or the server trusts its caller and a reverse proxy
5//! owns auth. There is no user model and no RBAC.
6//!
7//! When [`AppState::auth_token`](crate::AppState::auth_token) is set, this
8//! middleware requires `Authorization: Bearer <that token>` on every request
9//! and answers anything else with a `401` carrying the standard error
10//! envelope. When it is unset, the middleware is a pass-through.
11
12use axum::extract::{Request, State};
13use axum::http::header;
14use axum::middleware::Next;
15use axum::response::{IntoResponse, Response};
16
17use crate::error::ApiError;
18use crate::state::AppState;
19
20/// Rejects a request whose bearer token is missing or wrong, when a token is
21/// configured; otherwise passes it straight through.
22pub async fn require_bearer(
23    State(state): State<AppState>,
24    request: Request,
25    next: Next,
26) -> Response {
27    let Some(expected) = state.auth_token() else {
28        return next.run(request).await;
29    };
30    let presented = request
31        .headers()
32        .get(header::AUTHORIZATION)
33        .and_then(|value| value.to_str().ok());
34    if presented == Some(&format!("Bearer {expected}")) {
35        next.run(request).await
36    } else {
37        ApiError::Unauthorized.into_response()
38    }
39}