From ec70060ae5fa665953741da921e28031b56bc5e0 Mon Sep 17 00:00:00 2001 From: tv Date: Sat, 7 Nov 2026 22:35:09 +0100 Subject: auth: logging in, and tokens as bearers POST /auth/login (by htpasswd or the proxy), /auth/refresh, /auth/logout, GET /auth/whoami; every request may bring Authorization: Bearer instead of a password. --token-lifetime and --session-lifetime. Auth plan M2. --- src/api/auth.rs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'src/api/auth.rs') diff --git a/src/api/auth.rs b/src/api/auth.rs index f85b64e..69c7ddb 100644 --- a/src/api/auth.rs +++ b/src/api/auth.rs @@ -203,10 +203,16 @@ fn parse_basic(headers: &HeaderMap) -> Option<(String, String)> { Some((user.to_owned(), pass.to_owned())) } -/// The user a request authenticated as (a request extension, set by [`basic_auth`]). +/// The user a request authenticated as (a request extension, set by [`basic_auth`], or +/// by `login::bearer` for a token). #[derive(Clone, Debug)] pub(crate) struct AuthenticatedUser(pub(crate) String); +/// How the request's user proved who it is (a request extension, beside +/// `AuthenticatedUser`): `htpasswd`, `header` (a trusted proxy's), or `token`. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) struct Via(pub(crate) &'static str); + /// The user the trusted proxy the request came from names, if it does. fn proxied_user(state: &AuthState, headers: &HeaderMap, from: Option) -> Option { let proxy = state.proxy.as_ref()?; @@ -279,15 +285,21 @@ pub(crate) async fn basic_auth( mut request: Request, next: axum::middleware::Next, ) -> Response { + // A token, taken already (`login::bearer`). + if request.extensions().get::().is_some() { + return next.run(request).await; + } let from = request .extensions() .get::>() .map(|ConnectInfo(peer)| *peer); let user = match proxied_user(&state, &headers, from) { - Some(user) => Some(user), - None => authenticate(&state, &headers).await, + Some(user) => Some((user, Via("header"))), + None => authenticate(&state, &headers) + .await + .map(|user| (user, Via("htpasswd"))), }; - let Some(user) = user else { + let Some((user, via)) = user else { sleep(Duration::from_millis(1500)).await; // A challenge only where basic authentication can answer it. return match state.users { @@ -302,6 +314,7 @@ pub(crate) async fn basic_auth( }; request.extensions_mut().insert(AuthenticatedUser(user)); + request.extensions_mut().insert(via); next.run(request).await } -- cgit v1.3.1