aboutsummaryrefslogtreecommitdiffstats
path: root/src/api/mod.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/mod.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/mod.rs')
-rw-r--r--src/api/mod.rs18
1 files changed, 18 insertions, 0 deletions
diff --git a/src/api/mod.rs b/src/api/mod.rs
index 2a523a4..9405a06 100644
--- a/src/api/mod.rs
+++ b/src/api/mod.rs
@@ -68,6 +68,10 @@ pub(crate) fn router(state: AppState, auth_state: AuthState, debug_api: bool) ->
.route("/admin/config", get(config::get_config))
.route("/auth/login", axum::routing::post(login::login))
.route("/auth/refresh", axum::routing::post(login::refresh))
+ .route(
+ "/auth/session",
+ axum::routing::post(login::session).delete(login::end_session),
+ )
.route("/auth/logout", axum::routing::post(login::logout))
.route("/auth/whoami", get(login::whoami))
.route("/admin/users", get(users::list).post(users::add_several))
@@ -122,6 +126,8 @@ pub(crate) fn router(state: AppState, auth_state: AuthState, debug_api: bool) ->
.route("/auth/challenge", axum::routing::post(login::challenge))
.route("/auth/login/key", axum::routing::post(login::login_key))
.route("/health", get(health::node_health))
+ // To log in to the dashboard on, without authentication.
+ .route("/login", get(dashboard_login))
.route("/ready", get(health::ready))
// Outermost, so authentication failures get the error body too.
.layer(middleware::from_fn(json_errors))
@@ -262,6 +268,18 @@ async fn json_errors(request: Request, next: Next) -> Response {
Response::from_parts(parts, Body::from(body))
}
+/// `GET /login` (`dashboard::login_page`); without the dashboard, none.
+async fn dashboard_login() -> Response {
+ #[cfg(feature = "dashboard")]
+ {
+ dashboard::login_page().await.into_response()
+ }
+ #[cfg(not(feature = "dashboard"))]
+ {
+ StatusCode::NOT_FOUND.into_response()
+ }
+}
+
/// `GET /openapi.yaml`: the API description (`docs/openapi.yaml`, built in).
async fn openapi_spec() -> impl IntoResponse {
(