feat: add Keycloak authentication for dashboard and API endpoints (#2)
Some checks failed
CI / Clippy (push) Has been cancelled
CI / Format (push) Successful in 2s
CI / Security Audit (push) Has been cancelled
CI / Tests (push) Has been cancelled

Dashboard: OAuth2/OIDC login flow with PKCE, session-based auth middleware
protecting all server function endpoints, check-auth server function for
frontend auth state, login page gate in AppShell, user info in sidebar.

Agent API: JWT validation middleware using Keycloak JWKS endpoint,
conditionally enabled when KEYCLOAK_URL and KEYCLOAK_REALM are set.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Co-authored-by: Sharang Parnerkar <parnerkarsharang@gmail.com>
Reviewed-on: #2
This commit was merged in pull request #2.
This commit is contained in:
2026-03-07 23:50:56 +00:00
parent 42cabf0582
commit 0cb06d3d6d
21 changed files with 741 additions and 13 deletions

View File

@@ -0,0 +1,33 @@
use axum::{
extract::Request,
middleware::Next,
response::{IntoResponse, Response},
};
use reqwest::StatusCode;
use tower_sessions::Session;
use super::auth::LOGGED_IN_USER_SESS_KEY;
use super::user_state::UserStateInner;
const PUBLIC_API_ENDPOINTS: &[&str] = &["/api/check-auth"];
/// Axum middleware that enforces authentication on `/api/` server
/// function endpoints.
pub async fn require_auth(session: Session, request: Request, next: Next) -> Response {
let path = request.uri().path();
if path.starts_with("/api/") && !PUBLIC_API_ENDPOINTS.contains(&path) {
let is_authed = session
.get::<UserStateInner>(LOGGED_IN_USER_SESS_KEY)
.await
.ok()
.flatten()
.is_some();
if !is_authed {
return (StatusCode::UNAUTHORIZED, "Authentication required").into_response();
}
}
next.run(request).await
}