prospero_api/auth/
handlers.rs1use axum::Json;
4use axum::extract::State;
5use axum::http::{HeaderMap, StatusCode, header};
6use axum::response::{IntoResponse, Response};
7use prospero_types::{SessionInfo, SignInBody};
8
9use super::session::{self, SESSION_TTL_SECS};
10use super::{Principal, Via, resolve_principal};
11use crate::AppState;
12use crate::error::ApiError;
13
14fn info(p: &Principal) -> SessionInfo {
15 SessionInfo::Token {
16 token_name: p.token_name.clone(),
17 scope: p.scope,
18 expires_at: p
19 .expires_unix
20 .and_then(|s| chrono::DateTime::from_timestamp(s, 0))
21 .map(|d| d.to_rfc3339()),
22 }
23}
24
25pub async fn get_session(
27 State(st): State<AppState>,
28 headers: HeaderMap,
29) -> Result<Json<SessionInfo>, ApiError> {
30 if !st.auth.is_enabled() {
31 return Ok(Json(SessionInfo::Disabled));
32 }
33 let p = resolve_principal(&st.auth, &headers).ok_or(ApiError::Unauthorized)?;
34 Ok(Json(info(&p)))
35}
36
37pub async fn post_session(
39 State(st): State<AppState>,
40 headers: HeaderMap,
41 Json(body): Json<SignInBody>,
42) -> Result<Response, ApiError> {
43 let Some(tokens) = st.auth.tokens() else {
44 return Err(ApiError::NotFound("authentication is disabled".into()));
45 };
46 let entry = tokens
47 .authenticate(&body.token)
48 .ok_or(ApiError::Unauthorized)?;
49 let expires = chrono::Utc::now().timestamp() + SESSION_TTL_SECS;
50 let value = session::sign(st.auth.session_key(), entry, expires);
51 let secure = st.auth.cookie_secure() || session::is_https(&headers);
52 let principal = Principal {
53 token_name: entry.name.clone(),
54 scope: entry.scope,
55 via: Via::Cookie,
56 expires_unix: Some(expires),
57 };
58 tracing::info!(target: "prospero_audit", actor = %entry.name, "dashboard sign-in");
59 let mut response = Json(info(&principal)).into_response();
60 response.headers_mut().insert(
61 header::SET_COOKIE,
62 session::set_cookie(&value, SESSION_TTL_SECS, secure),
63 );
64 Ok(response)
65}
66
67pub async fn delete_session(State(st): State<AppState>, headers: HeaderMap) -> Response {
69 let secure = st.auth.cookie_secure() || session::is_https(&headers);
70 (
71 StatusCode::NO_CONTENT,
72 [(header::SET_COOKIE, session::clear_cookie(secure))],
73 )
74 .into_response()
75}