Skip to main content

postrust_proxy/saas/handlers/
auth.rs

1//! Authentication and API key management handlers.
2
3use crate::admin::api::ApiResponse;
4use crate::saas::auth::Auth;
5use crate::saas::handlers::{error_response, SaasState};
6use crate::saas::types::CreateApiKeyRequest;
7use axum::{
8    extract::{Path, State},
9    http::StatusCode,
10    response::IntoResponse,
11    Json,
12};
13use serde::Serialize;
14use uuid::Uuid;
15
16/// Create a new API key.
17pub async fn create_api_key(
18    State(state): State<SaasState>,
19    Auth(auth): Auth,
20    Json(req): Json<CreateApiKeyRequest>,
21) -> impl IntoResponse {
22    match state
23        .api_key_service
24        .create_api_key(auth.tenant_id, req)
25        .await
26    {
27        Ok(api_key) => (StatusCode::CREATED, Json(ApiResponse::success(api_key))).into_response(),
28        Err(e) => error_response(e).into_response(),
29    }
30}
31
32/// List API keys for the authenticated tenant.
33pub async fn list_api_keys(State(state): State<SaasState>, Auth(auth): Auth) -> impl IntoResponse {
34    match state.api_key_service.list_api_keys(auth.tenant_id).await {
35        Ok(keys) => Json(ApiResponse::success(keys)).into_response(),
36        Err(e) => error_response(e).into_response(),
37    }
38}
39
40/// Revoke (delete) an API key.
41pub async fn revoke_api_key(
42    State(state): State<SaasState>,
43    Auth(auth): Auth,
44    Path(id): Path<Uuid>,
45) -> impl IntoResponse {
46    match state
47        .api_key_service
48        .revoke_api_key(id, auth.tenant_id)
49        .await
50    {
51        Ok(true) => Json(ApiResponse::success(())).into_response(),
52        Ok(false) => (
53            StatusCode::NOT_FOUND,
54            Json(ApiResponse::<()>::error("API key not found")),
55        )
56            .into_response(),
57        Err(e) => error_response(e).into_response(),
58    }
59}
60
61/// Current tenant info response.
62#[derive(Serialize)]
63pub struct CurrentTenantResponse {
64    pub tenant_id: Uuid,
65    pub auth_type: String,
66    pub scopes: Vec<String>,
67}
68
69/// Get current tenant info.
70pub async fn get_current_tenant(Auth(auth): Auth) -> impl IntoResponse {
71    let auth_type = match &auth.auth_type {
72        crate::saas::auth::AuthType::Jwt { .. } => "jwt",
73        crate::saas::auth::AuthType::ApiKey { .. } => "api_key",
74    };
75
76    Json(ApiResponse::success(CurrentTenantResponse {
77        tenant_id: auth.tenant_id,
78        auth_type: auth_type.to_string(),
79        scopes: auth.scopes,
80    }))
81}
82
83/// Get tenant usage statistics.
84pub async fn get_tenant_usage(
85    State(state): State<SaasState>,
86    Auth(auth): Auth,
87) -> impl IntoResponse {
88    match state.domain_manager.get_tenant_usage(auth.tenant_id).await {
89        Ok(usage) => Json(ApiResponse::success(usage)).into_response(),
90        Err(e) => error_response(e).into_response(),
91    }
92}