aboutsummaryrefslogtreecommitdiffstats
path: root/src/api/auth.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-11-07 22:35:22 +0100
committertv <tv@krebsco.de>2026-11-07 22:35:22 +0100
commitb99e7ddf38233120ea19485968c12c5548e7fa61 (patch)
tree0dbd1fca28e979d76b54d38c446a70e082da9595 /src/api/auth.rs
parentc296fe8b2532f40c9a1f839ebdac2449e38342d5 (diff)
auth: a login page and browser sessions
GET /login without authentication: log in by password or with a token (from a login by key). POST/DELETE /auth/session keep the token as an HttpOnly, SameSite=Strict cookie; the dashboard sends a browser without a user there and renews the session while open. Auth plan M2/M3 (browsers).
Diffstat (limited to 'src/api/auth.rs')
-rw-r--r--src/api/auth.rs15
1 files changed, 15 insertions, 0 deletions
diff --git a/src/api/auth.rs b/src/api/auth.rs
index 69c7ddb..f28aa22 100644
--- a/src/api/auth.rs
+++ b/src/api/auth.rs
@@ -301,6 +301,21 @@ pub(crate) async fn basic_auth(
};
let Some((user, via)) = user else {
sleep(Duration::from_millis(1500)).await;
+ // A browser opening the dashboard: to the page to log in on.
+ if cfg!(feature = "dashboard")
+ && request.method() == axum::http::Method::GET
+ && request.uri().path() == "/admin/dashboard"
+ && headers
+ .get(axum::http::header::ACCEPT)
+ .and_then(|accept| accept.to_str().ok())
+ .is_some_and(|accept| accept.contains("text/html"))
+ {
+ return (
+ StatusCode::SEE_OTHER,
+ [(axum::http::header::LOCATION, "../login")],
+ )
+ .into_response();
+ }
// A challenge only where basic authentication can answer it.
return match state.users {
Some(_) => (