systemprompt-api 0.15.0

Axum-based HTTP server and API gateway for systemprompt.io AI governance infrastructure. Exposes governed agents, MCP, A2A, and admin endpoints with rate limiting and RBAC.
Documentation
use axum::extract::Path;
use axum::http::{HeaderMap, StatusCode};
use axum::response::{IntoResponse, Json, Response};
use systemprompt_models::Config;

use super::validation::validate_registration_token;
use crate::routes::oauth::OAuthHttpError;
use crate::routes::oauth::extractors::OAuthRepo;
use systemprompt_oauth::oauth::dynamic_registration::{
    DynamicRegistrationRequest, DynamicRegistrationResponse,
};

pub async fn update_client_configuration(
    OAuthRepo(repository): OAuthRepo,
    Path(client_id): Path<String>,
    headers: HeaderMap,
    Json(request): Json<DynamicRegistrationRequest>,
) -> Result<Response, OAuthHttpError> {
    let registration_token = validate_registration_token(&headers)?;

    let client_id = systemprompt_identifiers::ClientId::new(&client_id);
    let existing_client = repository
        .find_client_by_id(&client_id)
        .await?
        .ok_or_else(|| OAuthHttpError::invalid_client_metadata("Client not found"))?;

    let client_name = request
        .get_client_name()
        .map_err(OAuthHttpError::invalid_client_metadata)?;
    let mut redirect_uris = request
        .get_redirect_uris()
        .map_err(OAuthHttpError::invalid_client_metadata)?;
    redirect_uris.sort();
    redirect_uris.dedup();

    repository
        .update_client(
            &client_id,
            Some(&client_name),
            Some(&redirect_uris),
            Some(&existing_client.scopes),
        )
        .await
        .map_err(|e| {
            OAuthHttpError::invalid_client_metadata(format!("Failed to update client: {e}"))
        })?;

    let base_url = Config::get()
        .map_err(|e| OAuthHttpError::server_error(format!("Configuration unavailable: {e}")))?
        .api_server_url
        .clone();

    let response = DynamicRegistrationResponse {
        client_id: client_id.clone(),
        client_secret: "***REDACTED***".to_owned(),
        client_name,
        redirect_uris,
        grant_types: existing_client.grant_types,
        response_types: existing_client.response_types,
        scope: existing_client.scopes.join(" "),
        token_endpoint_auth_method: existing_client.token_endpoint_auth_method,
        application_type: existing_client.application_type,
        client_uri: request.client_uri,
        logo_uri: request.logo_uri,
        contacts: request.contacts,
        client_secret_expires_at: 0,
        client_id_issued_at: existing_client.created_at,
        registration_access_token: registration_token,
        registration_client_uri: format!("{base_url}/api/v1/core/oauth/register/{client_id}"),
    };

    Ok((StatusCode::OK, Json(response)).into_response())
}