mirror of
https://github.com/outbackdingo/optimclaw.git
synced 2026-08-26 15:40:18 +00:00
feat(web): DB-backed auth, user/token/invitation API handlers
Adds the web gateway layer for DB-backed user management (#1605): Auth refactor: - CombinedAuthState wraps env-var tokens (MultiAuthState) + optional DbAuthenticator for DB-backed token lookup with LRU cache (60s TTL, 1024 max entries) - auth_middleware tries env-var tokens first, then DB fallback - From<MultiAuthState> impl for backward compatibility - main.rs wires with_db_auth when database is available API handlers (12 new endpoints): - /api/admin/users — CRUD: create, list, detail, update, suspend, activate - /api/tokens — create (returns plaintext once), list, revoke - /api/invitations — create, list, accept (creates user + first token) Token creation: 32 random bytes → hex plaintext, SHA-256 hash stored. Invitation accept: validates hash + pending + not expired, creates user record and first API token atomically. All test files updated for CombinedAuthState type change. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
This commit is contained in:
@@ -73,7 +73,10 @@ fn user_echo_app(auth: MultiAuthState) -> Router {
|
||||
.route("/api/whoami/scopes", get(echo_user_with_scopes))
|
||||
.route("/api/action", post(echo_user))
|
||||
.route("/api/chat/events", get(echo_user)) // SSE endpoint (allows query token)
|
||||
.layer(middleware::from_fn_with_state(auth, auth_middleware))
|
||||
.layer(middleware::from_fn_with_state(
|
||||
ironclaw::channels::web::auth::CombinedAuthState::from(auth),
|
||||
auth_middleware,
|
||||
))
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
@@ -905,7 +908,7 @@ async fn start_multi_user_server_with_db() -> (
|
||||
});
|
||||
|
||||
let addr: SocketAddr = "127.0.0.1:0".parse().unwrap();
|
||||
let bound = ironclaw::channels::web::server::start_server(addr, state.clone(), auth)
|
||||
let bound = ironclaw::channels::web::server::start_server(addr, state.clone(), auth.into())
|
||||
.await
|
||||
.expect("Failed to start server with DB");
|
||||
|
||||
|
||||
@@ -224,7 +224,7 @@ async fn start_test_server_with_provider(
|
||||
"test-user".to_string(),
|
||||
);
|
||||
let addr: SocketAddr = "127.0.0.1:0".parse().unwrap();
|
||||
let bound_addr = start_server(addr, state.clone(), auth)
|
||||
let bound_addr = start_server(addr, state.clone(), auth.into())
|
||||
.await
|
||||
.expect("Failed to start test server");
|
||||
|
||||
@@ -722,7 +722,7 @@ async fn test_no_llm_provider_returns_503() {
|
||||
"test-user".to_string(),
|
||||
);
|
||||
let addr: SocketAddr = "127.0.0.1:0".parse().unwrap();
|
||||
let bound_addr = start_server(addr, state, auth).await.unwrap();
|
||||
let bound_addr = start_server(addr, state, auth.into()).await.unwrap();
|
||||
|
||||
let url = format!("http://{}/v1/chat/completions", bound_addr);
|
||||
let resp = client()
|
||||
@@ -760,7 +760,7 @@ async fn test_chat_completions_body_too_large() {
|
||||
post(ironclaw::channels::web::openai_compat::chat_completions_handler),
|
||||
)
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
auth_state,
|
||||
ironclaw::channels::web::auth::CombinedAuthState::from(auth_state),
|
||||
ironclaw::channels::web::auth::auth_middleware,
|
||||
))
|
||||
.layer(DefaultBodyLimit::max(10 * 1024 * 1024))
|
||||
|
||||
@@ -297,7 +297,7 @@ impl GatewayWorkflowHarness {
|
||||
let addr = start_server(
|
||||
"127.0.0.1:0".parse().expect("valid localhost addr"),
|
||||
Arc::clone(&gateway_state),
|
||||
auth,
|
||||
auth.into(),
|
||||
)
|
||||
.await
|
||||
.expect("failed to start gateway server");
|
||||
|
||||
@@ -72,7 +72,7 @@ async fn start_test_server() -> (
|
||||
"test-user".to_string(),
|
||||
);
|
||||
let addr: SocketAddr = "127.0.0.1:0".parse().unwrap();
|
||||
let bound_addr = start_server(addr, state.clone(), auth)
|
||||
let bound_addr = start_server(addr, state.clone(), auth.into())
|
||||
.await
|
||||
.expect("Failed to start test server");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user