Skip to main content

Agentic Identity Broker - Admin Server API (1.0.0)

Download OpenAPI specification:Download

License: MIT

Administrative REST APIs for the Agentic Identity Broker running on Port 14000.

Overview

The Admin Server provides full CRUD operations for managing:

  • AI Agents: Registry of agents that can request delegated user permissions
  • Third-Party OAuth2 Services: External OAuth2 providers (GitHub, Google, Databricks, etc.)
  • System Health: Monitoring and health check endpoints

Dual-Port Architecture

The Agentic Identity Broker uses a dual-port HTTP server architecture:

  • Port 8000 (default): End-user server for consent management
  • Port 14000 (default): Admin server for configuration (this API)

Authentication & Authorization

All endpoints require authentication via reverse proxy (oauth2-proxy, nginx, etc.). The proxy validates user credentials and sets the principal identifier in the X-Remote-User header (configurable via auth.principal_header).

  • Admin endpoints: Require administrative privileges (enforced at proxy level)
  • Health endpoint: Public, no authentication required

Security Considerations

Client Secret Protection (SR-003)

  • Client secrets are NEVER transmitted in plaintext to the frontend
  • All API responses redact secrets with the value "REDACTED"
  • Secrets are encrypted at rest using AES-256-GCM
  • Update operations support secret rotation

URL Validation

  • All URLs must use HTTP or HTTPS schemes
  • OAuth2 issuer URIs must use HTTPS
  • Metadata URLs must use HTTPS
  • URL validation prevents injection attacks

Referential Integrity

  • Services cannot be deleted if user grants reference them (409 Conflict)
  • Agent deletion cascades to associated grants (logged for audit)

OAuth2 Discovery Support

Services can be configured with automatic endpoint discovery:

  • Enabled: System fetches endpoints from {issuer_uri}/.well-known/oauth-authorization-server
  • Disabled: Requires manual token_endpoint and authorize_endpoint configuration
  • Metadata URL: Optional override for non-standard discovery locations

Trace Correlation

By default, every HTTP response from this API includes the additive W3C traceresponse response header.

  • The header applies globally across this API, including successful responses and error responses.
  • Its <trace-id> field is the request correlation identifier operators can use to find matching logs.
  • The header is additive only; no request or response body schema changes are introduced by this feature.
  • Emission is enabled by default and can be disabled only through request_context.trace.response_enabled.

Error Handling

All error responses follow a consistent format with appropriate HTTP status codes. See the ErrorResponse schema for details.

Health

Health check and monitoring endpoints

Health check endpoint

Returns the current health status of the HTTP server. Each server (end-user and admin) has its own independent health endpoint that reports only that server's status.

This endpoint is public and does not require authentication.

Status Codes:

  • 200 OK: Server is healthy and accepting requests
  • 503 Service Unavailable: Server is starting, shutting down, or unhealthy

Health States:

  • healthy: Server is operational and processing requests normally
  • starting: Server is initializing (binding to port, setting up routes)
  • shutting_down: Graceful shutdown in progress, completing in-flight requests
  • unhealthy: Server encountered an error and requires restart

Responses

Response samples

Content type
application/json
{
  • "status": "healthy",
  • "timestamp": "2025-12-19T10:30:00Z",
  • "uptime_seconds": 3600
}

Agents

Administrative operations for AI agent registry management

List all agents

Retrieve a list of all registered agents in the system.

Returns a direct array of agent objects (no envelope). Agents are returned in no guaranteed order.

Authorizations:
PreAuthProxy
header Parameters
Prefer
string
Example: reference-id=canonical

Request canonical rendering of nested service and permission-set references. The default representation uses UUIDs. May be combined with other Prefer preferences (e.g. return=minimal, reference-id=canonical); unrecognized preferences are ignored.

Responses

Response samples

Content type
application/json
Example
[
  • {
    },
  • {
    }
]

Create a new agent

Register a new AI agent in the identity broker system.

The client_id field is the upstream OAuth2 client ID used when proxying authorization requests to the upstream server.

client_id uniqueness depends on configuration:

  • When multi_agent_client.enabled = false (default): client_id must be unique across all agents. Returns 409 Conflict if a duplicate client_id is detected.
  • When multi_agent_client.enabled = true: Multiple agents may share the same client_id. No uniqueness validation is performed.

Validation Rules:

  • client_id: Optional; when provided must be non-empty; unique across all agents when multi_agent_client.enabled = false
  • display_name: Required, max 255 characters
  • description: Required, max 1000 characters
  • URLs: Must be valid HTTP/HTTPS URLs if provided

ID Generation: System generates a UUID for the agent ID. client_id is not auto-generated — omit it for agents that do not need one.

Authorizations:
PreAuthProxy
Request Body schema: application/json
required
canonical_id
string or null [ 1 .. 128 ] characters ^[A-Za-z0-9._-]+$
client_id
string <= 255 characters

OAuth2 client_id for this agent. Optional — omit for agents resolved via client_uris (CIMD) or agents that do not need an upstream client_id. When provided, must be non-empty.

external_id
string or null <= 255 characters

Optional external governance system identifier

display_name
required
string [ 1 .. 255 ] characters

Human-readable name for the agent

description
required
string [ 1 .. 1000 ] characters

Detailed description of the agent's purpose and capabilities

governance_url
string or null <uri>

URL to governance and compliance information (must be HTTP/HTTPS)

user_documentation_url
string or null <uri>

URL to user-facing documentation (must be HTTP/HTTPS)

agent_interface_url
string or null <uri>

URL where users can interact with the agent (must be HTTP/HTTPS)

Array of objects or null (ServiceRequirementRequest)

List of third-party OAuth2 services that the agent requires access to. Referential integrity is validated: service_id must exist and supplied required_scopes must match the service definition. Omit or provide an empty list for scope-less services.

required
Array of objects (AgentPermissionSetEntry) non-empty

List of permission set declarations for this agent (FR-006). Must contain at least one entry — an empty list or omitted field is a 400 error. All referenced permission_set_id values must exist.

redirect_uris
Array of strings or null <uri> [ items <uri > ]

List of allowed redirect URIs for OAuth2 authorization code flow. When the broker acts as an OAuth2 server, only these URIs are accepted as valid redirect targets for this agent.

allowed_scopes
Array of strings or null

List of OAuth2 scopes that this agent is permitted to request when the broker acts as an OAuth2 authorization server.

client_uris
Array of strings or null <uri> [ items <uri > ]

Pre-registered Client ID Metadata Document URLs for this agent. Each entry must be a globally unique HTTPS URL. A * can replace one complete, non-empty path segment. The broker uses an exact entry before matching patterns. It rejects ambiguous pattern matches and URI paths containing literal \, %2F, or %5C. Returns 400 for malformed URLs. Returns 409 Conflict when a URI is already registered to a different agent.

Responses

Request samples

Content type
application/json
Example
{
  • "client_id": "agent-simple-assistant",
  • "display_name": "Simple Assistant",
  • "description": "A basic AI assistant for general tasks",
  • "permission_sets": [
    ]
}

Response samples

Content type
application/json
{}

Get agent by ID

Retrieve detailed information about a specific agent.

Returns the complete agent configuration including all optional fields.

Authorizations:
PreAuthProxy
path Parameters
agent-id
required
string
Examples:
  • 550e8400-e29b-41d4-a716-446655440000 -
  • research-agent -

UUID or canonical identifier of the agent

header Parameters
Prefer
string
Example: reference-id=canonical

Request canonical rendering of nested service and permission-set references. The default representation uses UUIDs. May be combined with other Prefer preferences (e.g. return=minimal, reference-id=canonical); unrecognized preferences are ignored.

Responses

Response samples

Content type
application/json
{
  • "id": "550e8400-e29b-41d4-a716-446655440000",
  • "client_id": "agent-research-assistant",
  • "display_name": "Research Assistant",
  • "description": "AI assistant that helps with academic research",
  • "permission_sets": [
    ],
  • "created_at": "2025-12-19T10:30:00Z",
  • "updated_at": "2025-12-19T10:30:00Z"
}

Update agent

Update configuration for an existing agent.

Update Semantics:

  • All fields in the request body will update the agent
  • Omitted optional fields are preserved from existing configuration
  • created_at timestamp is preserved
  • updated_at timestamp is set to current time

client_id uniqueness depends on configuration:

  • When multi_agent_client.enabled = false (default): client_id must be unique across all agents (excluding the current agent). Returns 409 Conflict if a duplicate client_id is detected on another agent.
  • When multi_agent_client.enabled = true: Multiple agents may share the same client_id. No uniqueness validation is performed.

Validation:

  • client_id: Three-state — omitted preserves existing value, explicit null clears it, string value updates it (must be non-empty); unique across all agents (excluding the current agent) when multi_agent_client.enabled = false
  • Other fields follow the same rules as creation
Authorizations:
PreAuthProxy
path Parameters
agent-id
required
string
Examples:
  • 550e8400-e29b-41d4-a716-446655440000 -
  • research-agent -

UUID or canonical identifier of the agent

Request Body schema: application/json
required
canonical_id
string or null [ 1 .. 128 ] characters ^[A-Za-z0-9._-]+$

Omitted preserves the current canonical ID; null removes it; a string replaces it.

client_id
string or null <= 255 characters

OAuth2 client_id for this agent.

Three-state semantics:

  • Omitted (key absent from JSON): existing value is preserved
  • Explicit null ("client_id": null): clears the client_id (sets to NULL)
  • String value ("client_id": "foo"): updates the client_id; must be non-empty

Agents without a client_id cannot participate in proxy-mode OAuth2 flows.

external_id
string or null <= 255 characters

Optional external governance system identifier

display_name
required
string [ 1 .. 255 ] characters

Human-readable name for the agent

description
required
string [ 1 .. 1000 ] characters

Detailed description of the agent's purpose and capabilities

governance_url
string or null <uri>

URL to governance and compliance information (must be HTTP/HTTPS)

user_documentation_url
string or null <uri>

URL to user-facing documentation (must be HTTP/HTTPS)

agent_interface_url
string or null <uri>

URL where users can interact with the agent (must be HTTP/HTTPS)

Array of objects or null (ServiceRequirementRequest)

List of third-party OAuth2 services that the agent requires access to. Referential integrity is validated: service_id must exist and supplied required_scopes must match the service definition. Omit or provide an empty list for scope-less services.

required
Array of objects (AgentPermissionSetEntry) non-empty

List of permission set declarations for this agent (FR-006). Must contain at least one entry — an empty list or omitted field is a 400 error. All referenced permission_set_id values must exist.

redirect_uris
Array of strings or null <uri> [ items <uri > ]

List of allowed redirect URIs for OAuth2 authorization code flow. When the broker acts as an OAuth2 server, only these URIs are accepted as valid redirect targets for this agent.

allowed_scopes
Array of strings or null

List of OAuth2 scopes that this agent is permitted to request when the broker acts as an OAuth2 authorization server.

client_uris
Array of strings or null <uri> [ items <uri > ]

Pre-registered Client ID Metadata Document URLs for this agent. Replaces the previous list on PUT (full replacement semantics). Each entry must be a globally unique HTTPS URL. A * can replace one complete, non-empty path segment. The broker uses an exact entry before matching patterns. It rejects ambiguous pattern matches and URI paths containing literal \, %2F, or %5C. Returns 400 for malformed URLs. Returns 409 Conflict when a URI is already registered to a different agent.

Responses

Request samples

Content type
application/json
Example
{
  • "client_id": "agent-research-assistant",
  • "display_name": "Advanced Research Assistant",
  • "description": "AI assistant that helps with academic research",
  • "permission_sets": [
    ]
}

Response samples

Content type
application/json
{
  • "id": "550e8400-e29b-41d4-a716-446655440000",
  • "client_id": "agent-research-assistant",
  • "display_name": "Advanced Research Assistant",
  • "description": "AI assistant that helps with academic research",
  • "permission_sets": [
    ],
  • "created_at": "2025-12-19T10:30:00Z",
  • "updated_at": "2025-12-19T15:45:00Z"
}

Delete agent

Remove an agent from the system.

Cascade Behavior:

  • All user grants associated with this agent are automatically deleted
  • Deletion is logged for audit purposes

Irreversible: This operation cannot be undone

Authorizations:
PreAuthProxy
path Parameters
agent-id
required
string
Examples:
  • 550e8400-e29b-41d4-a716-446655440000 -
  • research-agent -

UUID or canonical identifier of the agent

Responses

Response samples

Content type
application/json
{
  • "error": "agent ID is required"
}

Services

Administrative operations for third-party OAuth2 service configurations

List all OAuth2 services

Retrieve a list of all configured third-party OAuth2 services.

Returns a direct array of service objects (no envelope).

Security: All client_secret fields are redacted as "REDACTED" for confidential services; the property is omitted for public services, which hold no credential

Authorizations:
PreAuthProxy
header Parameters
Prefer
string
Example: reference-id=canonical

Request canonical rendering of nested service and permission-set references. The default representation uses UUIDs. May be combined with other Prefer preferences (e.g. return=minimal, reference-id=canonical); unrecognized preferences are ignored.

Responses

Response samples

Content type
application/json
Example
[
  • {
    },
  • {}
]

Create a new OAuth2 service

Configure a new third-party OAuth2 service provider.

Validation Rules:

  • display_name: Required, max 255 characters
  • client_id: Required, unique across all services
  • client_secret: Required unless token_endpoint_auth_method is none (encrypted at rest, never returned)
  • issuer_uri: Required, must be HTTPS URL
  • scopes: Optional. Omit it or provide an empty array when the provider does not use OAuth2 scopes.

Discovery Modes:

  1. Automatic Discovery (enable_discovery: true):

    • System fetches endpoints from {issuer_uri}/.well-known/oauth-authorization-server
    • Optional metadata_url can override default discovery location
    • Falls back to manual endpoints if discovery fails
  2. Manual Configuration (enable_discovery: false):

    • Requires endpoints.token_endpoint and endpoints.authorize_endpoint

Security: client_secret is encrypted with AES-256-GCM before storage

Authorizations:
PreAuthProxy
Request Body schema: application/json
required
canonical_id
string or null [ 1 .. 128 ] characters ^[A-Za-z0-9._-]+$
display_name
required
string [ 1 .. 255 ] characters

Human-readable name for the service

oauth2_flavor
string
Default: "standard"
Enum: "standard" "google" "github"

OAuth2 authentication variant. Defaults to standard if omitted. Auto-detected as github when the token endpoint host equals github.com.

  • standard: client_secret must be a non-empty plain string; client_id is required
  • google: client_secret must be a valid Google service account JSON key (≤32 KB); client_id is derived from the JSON's client_id field and need not be provided; issuer_uri is optional; endpoints are derived from the service account JSON
  • github: Same as standard but scopes in token responses are parsed as comma-separated
client_id
string non-empty

OAuth2 client_id for this service.

Required when oauth2_flavor is standard or github. Optional when oauth2_flavor is google — automatically extracted from the service account JSON.

client_secret
string or null

Authentication credential for this service.

The content depends on oauth2_flavor:

  • standard / github: Non-empty OAuth2 client secret string
  • google: Serialized Google service account JSON key document. Must contain: type (must be "service_account"), private_key (non-empty), client_email (non-empty), token_uri (non-empty), client_id (non-empty). Maximum size: 32 KB.

SECURITY: Encrypted at rest using AES-256-GCM. Never returned in API responses (always "REDACTED").

Conditionally required: If token_endpoint_auth_method is omitted or null, client_secret is REQUIRED and must contain a non-empty value.

If token_endpoint_auth_method is none, this property can be omitted or set to null or "". A non-empty value returns 400. The broker never stores a secret for a public service.

token_endpoint_auth_method
string or null
Enum: "none" null

Declares that the upstream token endpoint expects no client authentication, making this service a public client (RFC 6749 §2.1, RFC 7591 token_endpoint_auth_method).

Omit this property, or send null, for a confidential client; there is no default and no value is ever inferred or assigned on your behalf. null means exactly what omission means, so the null this property carries in a read response can be submitted straight back in an update without special handling.

When none:

  • client_secret can be omitted, set to null, or set to "". It MUST NOT contain a non-empty value.
  • client_id is still REQUIRED; it is the only identity presented upstream.
  • oauth2_flavor: google is REJECTED, because the Google variant derives its client identifier from the credential document and a public service has none.
issuer_uri
string <uri>

OAuth2 issuer URI.

Required when oauth2_flavor is standard (must be HTTPS). Optional when oauth2_flavor is google. If provided, its scheme and host must match the token_uri in the service account JSON. If omitted, the token_uri from the service account JSON serves as the token endpoint.

required
object (DiscoveryConfigRequest)
object (OAuth2EndpointsRequest)

OAuth2 endpoints configuration.

Required when discovery.enable_discovery = false Optional when discovery.enable_discovery = true (used as fallback)

Each supplied token_endpoint and authorize_endpoint must use HTTPS. Under the default strict policy, HTTP is accepted only for localhost, 127.0.0.1, or [::1]; HTTP is accepted for any host only when security.skip_thirdparty_https_validation is enabled for development/test.

Array of objects (OAuth2ScopeRequest)

Optional OAuth2 scopes for this service. Omit or provide an empty array when the provider does not use scopes.

protected_resources
Array of strings <uri> [ items <uri > ]

List of protected resource URIs for RFC 8693 token exchange (optional). These URIs identify which resources this service can provide tokens for. URIs are normalized (trailing slashes removed) for consistent matching.

object

Static provider authorization parameters. Broker-owned OAuth2 names are rejected.

Responses

Request samples

Content type
application/json
Example
{
  • "display_name": "GitHub Production",
  • "client_id": "Iv1.1234567890abcdef",
  • "client_secret": "ghp_secretkey1234567890abcdef",
  • "issuer_uri": "https://github.com",
  • "discovery": {
    },
  • "scopes": [
    ]
}

Response samples

Content type
application/json
{
  • "id": "770e8400-e29b-41d4-a716-446655440002",
  • "display_name": "GitHub Production",
  • "client_id": "Iv1.1234567890abcdef",
  • "client_secret": "REDACTED",
  • "token_endpoint_auth_method": null,
  • "issuer_uri": "https://github.com",
  • "discovery": {
    },
  • "endpoints": {},
  • "scopes": [
    ],
  • "created_at": "2025-12-19T10:30:00Z",
  • "updated_at": "2025-12-19T10:30:00Z"
}

Get OAuth2 service by ID

Retrieve detailed configuration for a specific OAuth2 service.

Security: All client_secret fields are redacted as "REDACTED" for confidential services; the property is omitted for public services, which hold no credential

Authorizations:
PreAuthProxy
path Parameters
service-id
required
string
Examples:
  • 770e8400-e29b-41d4-a716-446655440002 -
  • github-prod -

UUID or canonical identifier of the OAuth2 service

header Parameters
Prefer
string
Example: reference-id=canonical

Request canonical rendering of nested service and permission-set references. The default representation uses UUIDs. May be combined with other Prefer preferences (e.g. return=minimal, reference-id=canonical); unrecognized preferences are ignored.

Responses

Response samples

Content type
application/json
{
  • "id": "770e8400-e29b-41d4-a716-446655440002",
  • "display_name": "GitHub Production",
  • "client_id": "Iv1.1234567890abcdef",
  • "client_secret": "REDACTED",
  • "token_endpoint_auth_method": null,
  • "issuer_uri": "https://github.com",
  • "discovery": {
    },
  • "endpoints": {},
  • "scopes": [
    ],
  • "created_at": "2025-12-19T10:30:00Z",
  • "updated_at": "2025-12-19T10:30:00Z"
}

Update OAuth2 service

Update configuration for an existing OAuth2 service.

Update Semantics:

  • All fields in the request body will update the service
  • Omitted optional fields are preserved from existing configuration
  • token_endpoint_auth_method is evaluated from the request alone. Omit it or set it to null to make the service confidential, regardless of its stored value; a client_secret is then required.
  • Updating a service to token_endpoint_auth_method: none removes the stored credential.
  • created_at timestamp is preserved
  • updated_at timestamp is set to current time

Secret Rotation:

  • Provide new client_secret to rotate credentials
  • New secret is encrypted before storage
  • Old secret is securely discarded

Discovery Re-run:

  • If enable_discovery: true, endpoints are re-fetched
  • Useful for services that change endpoint URLs

Security: client_secret is redacted in response

  • protected_resources omitted or null: preserves the current protected-resource set
  • protected_resources present (including []): replaces the entire set and requires If-Match
Authorizations:
PreAuthProxy
path Parameters
service-id
required
string
Examples:
  • 770e8400-e29b-41d4-a716-446655440002 -
  • github-prod -

UUID or canonical identifier of the OAuth2 service

header Parameters
If-Match
string

Required when a service update request includes protected_resources, because that field replaces the complete set. Supply the current strong service ETag from a prior GET or protected-resource collection GET. Omit it only when protected_resources is omitted or null; a missing required header returns 428 and a stale value returns 412.

Request Body schema: application/json
required
canonical_id
string or null [ 1 .. 128 ] characters ^[A-Za-z0-9._-]+$

Omitted preserves the current canonical ID; null removes it; a string replaces it.

display_name
required
string [ 1 .. 255 ] characters

Human-readable name for the service

oauth2_flavor
string
Default: "standard"
Enum: "standard" "google" "github"

OAuth2 authentication variant. Defaults to standard if omitted. Auto-detected as github when the token endpoint host equals github.com.

  • standard: client_secret must be a non-empty plain string; client_id is required
  • google: client_secret must be a valid Google service account JSON key (≤32 KB); client_id is derived from the JSON's client_id field and need not be provided; issuer_uri is optional; endpoints are derived from the service account JSON
  • github: Same as standard but scopes in token responses are parsed as comma-separated
client_id
string non-empty

OAuth2 client_id for this service.

Required when oauth2_flavor is standard or github. Optional when oauth2_flavor is google — automatically extracted from the service account JSON.

client_secret
string or null

Authentication credential for this service (provide new value to rotate).

The content depends on oauth2_flavor:

  • standard / github: Non-empty OAuth2 client secret string
  • google: Serialized Google service account JSON key document (≤32 KB)

SECURITY: Encrypted at rest, never returned in responses.

Conditionally required: If token_endpoint_auth_method is omitted or null, client_secret is REQUIRED and must contain a non-empty value.

If token_endpoint_auth_method is none, this property can be omitted or set to null or "". A non-empty value returns 400. The broker never stores a secret for a public service.

token_endpoint_auth_method
string or null
Enum: "none" null

Declares that the upstream token endpoint expects no client authentication, making this service a public client (RFC 6749 §2.1, RFC 7591 token_endpoint_auth_method).

Omit this property, or send null, for a confidential client; there is no default and no value is ever inferred or assigned on your behalf. null means exactly what omission means, so the null this property carries in a read response can be submitted straight back in an update without special handling.

When none:

  • client_secret can be omitted, set to null, or set to "". It MUST NOT contain a non-empty value.
  • client_id is still REQUIRED; it is the only identity presented upstream.
  • oauth2_flavor: google is REJECTED, because the Google variant derives its client identifier from the credential document and a public service has none.

Full replacement: this request replaces the service representation in full. The method is evaluated from the request alone — omitting it, or sending null, makes the updated service confidential regardless of its stored value, and the request is therefore rejected unless it also supplies a client_secret. This mirrors the existing rule that the client secret must be re-sent on every update. Updating a confidential service to none REMOVES the stored credential, leaving no dormant secret.

issuer_uri
string <uri>

OAuth2 issuer URI.

Required when oauth2_flavor is standard (must be HTTPS). Optional when oauth2_flavor is google. If provided, its scheme and host must match the token_uri in the service account JSON.

required
object (DiscoveryConfigRequest)
object (OAuth2EndpointsRequest)

OAuth2 endpoints configuration.

Required when discovery.enable_discovery = false Optional when discovery.enable_discovery = true (used as fallback)

Each supplied token_endpoint and authorize_endpoint must use HTTPS. Under the default strict policy, HTTP is accepted only for localhost, 127.0.0.1, or [::1]; HTTP is accepted for any host only when security.skip_thirdparty_https_validation is enabled for development/test.

Array of objects (OAuth2ScopeRequest)

Optional OAuth2 scopes for this service. Omit or provide an empty array when the provider does not use scopes.

protected_resources
Array of strings or null <uri> [ items <uri > ]

Optional protected resource URIs for RFC 8693 token exchange. Omit or set to null to preserve the current set. When present, including an empty array, this field authoritatively replaces the entire set and requires the If-Match header with the service's current strong ETag. URIs are normalized by trailing-slash trim before matching; an empty array clears the set.

object

Static provider authorization parameters. Omission preserves the current map; an empty object clears it.

Responses

Request samples

Content type
application/json
Example
{
  • "display_name": "GitHub Production",
  • "client_id": "Iv1.1234567890abcdef",
  • "client_secret": "ghp_newsecretkey9876543210zyxwvu",
  • "issuer_uri": "https://github.com",
  • "discovery": {
    },
  • "scopes": [
    ]
}

Response samples

Content type
application/json
{
  • "id": "770e8400-e29b-41d4-a716-446655440002",
  • "display_name": "GitHub Production",
  • "client_id": "Iv1.1234567890abcdef",
  • "client_secret": "REDACTED",
  • "token_endpoint_auth_method": null,
  • "issuer_uri": "https://github.com",
  • "discovery": {
    },
  • "endpoints": {},
  • "scopes": [
    ],
  • "created_at": "2025-12-19T10:30:00Z",
  • "updated_at": "2025-12-19T16:00:00Z"
}

Delete OAuth2 service

Remove an OAuth2 service from the system.

Referential Integrity Check:

  • Operation fails with 409 Conflict if user grants reference this service
  • Administrators must revoke or modify grants before deletion
  • This prevents breaking active user permissions

Irreversible: This operation cannot be undone

Authorizations:
PreAuthProxy
path Parameters
service-id
required
string
Examples:
  • 770e8400-e29b-41d4-a716-446655440002 -
  • github-prod -

UUID or canonical identifier of the OAuth2 service

Responses

Response samples

Content type
application/json
{
  • "error": "client ID is required"
}

List a service's protected resources

Authorizations:
PreAuthProxy
path Parameters
service-id
required
string
Examples:
  • 770e8400-e29b-41d4-a716-446655440002 -
  • github-prod -

UUID or canonical identifier of the OAuth2 service

Responses

Response samples

Content type
application/json
{}

Add one protected resource from the collection

Adds the body resource_uri after server-side validation and normalization. A newly added URI returns 201. A URI already owned by this service returns 200 with the set unchanged; a URI owned by another service returns 409 Conflict.

Authorizations:
PreAuthProxy
path Parameters
service-id
required
string
Examples:
  • 770e8400-e29b-41d4-a716-446655440002 -
  • github-prod -

UUID or canonical identifier of the OAuth2 service

Request Body schema: application/json
required
resource_uri
required
string <uri>

Absolute resource URI (scheme and host required), normalized by trailing-slash trim.

Responses

Request samples

Content type
application/json
{}

Response samples

Content type
application/json
{}

Add one protected resource

Idempotently adds the resource URI identified by the fully percent-encoded final path segment. The server decodes the segment exactly once, then validates and normalizes it. Adding a URI this service already owns returns 200 with the set unchanged; a URI owned by another service returns 409.

Authorizations:
PreAuthProxy
path Parameters
service-id
required
string
Examples:
  • 770e8400-e29b-41d4-a716-446655440002 -
  • github-prod -

UUID or canonical identifier of the OAuth2 service

resource
required
string
Example: https%3A%2F%2Fapi.example.com%2Fv2

Normalized protected resource URI, fully RFC 3986 percent-encoded as one path segment (: to %3A, / to %2F, ? to %3F, and # to %23). The server preserves the escaped segment, decodes it exactly once, then validates it as an absolute URI and normalizes its trailing slash.

Responses

Response samples

Content type
application/json
{}

Rename a protected resource in place

Atomically changes the percent-encoded source URI in {resource} to the target URI in the body. A source equal to the normalized target succeeds as a no-op. A target already owned by any service returns 409; a source not owned by this service returns 404.

Authorizations:
PreAuthProxy
path Parameters
service-id
required
string
Examples:
  • 770e8400-e29b-41d4-a716-446655440002 -
  • github-prod -

UUID or canonical identifier of the OAuth2 service

resource
required
string
Example: https%3A%2F%2Fapi.example.com%2Fv2

Normalized protected resource URI, fully RFC 3986 percent-encoded as one path segment (: to %3A, / to %2F, ? to %3F, and # to %23). The server preserves the escaped segment, decodes it exactly once, then validates it as an absolute URI and normalizes its trailing slash.

Request Body schema: application/json
required
to
required
string <uri>

Absolute target URI (scheme and host required), normalized by trailing-slash trim.

Responses

Request samples

Content type
application/json

Response samples

Content type
application/json
{}

Remove one protected resource

Removes the resource identified by the fully percent-encoded path segment after decoding exactly once and normalizing it. A resource not owned by this service returns 404.

Authorizations:
PreAuthProxy
path Parameters
service-id
required
string
Examples:
  • 770e8400-e29b-41d4-a716-446655440002 -
  • github-prod -

UUID or canonical identifier of the OAuth2 service

resource
required
string
Example: https%3A%2F%2Fapi.example.com%2Fv2

Normalized protected resource URI, fully RFC 3986 percent-encoded as one path segment (: to %3A, / to %2F, ? to %3F, and # to %23). The server preserves the escaped segment, decodes it exactly once, then validates it as an absolute URI and normalizes its trailing slash.

Responses

Response samples

Content type
application/json
{}

PermissionSets

CRUD operations for permission set management

Create a permission set

Creates a new named permission set grouping OAuth2 scopes across one or more third-party services.

Validation rules:

  • name must be unique (409 Conflict if duplicate)
  • service_scopes must contain at least one entry (400)
  • Each service_id in service_scopes must reference an existing service (400)
  • Each scopes list may be empty for a scope-less service; supplied values must be non-empty (400)
Authorizations:
PreAuthProxy
Request Body schema: application/json
required
canonical_id
string or null [ 1 .. 128 ] characters ^[A-Za-z0-9._-]+$
name
required
string <= 255 characters

Unique human-readable name for the permission set

description
required
string

Human-readable explanation of what capabilities this set grants

required
Array of objects (ServiceScope) non-empty

One or more service/scope entries covered by this permission set

Responses

Request samples

Content type
application/json
{
  • "canonical_id": "github-read",
  • "name": "GitHub Read Access",
  • "description": "Read repository contents and user profile from GitHub",
  • "service_scopes": [
    ]
}

Response samples

Content type
application/json
{
  • "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  • "canonical_id": "github-read",
  • "name": "GitHub Read Access",
  • "description": "Read repository contents and user profile from GitHub",
  • "service_scopes": [
    ],
  • "created_at": "2026-03-25T12:00:00Z",
  • "updated_at": "2026-03-25T12:00:00Z"
}

List permission sets

Returns all permission sets. Optionally filter by service ID to find all permission sets that include scopes for a specific third-party service.

Authorizations:
PreAuthProxy
query Parameters
service_id
string

UUID or canonical identifier of the service used to filter permission sets

header Parameters
Prefer
string
Example: reference-id=canonical

Request canonical rendering of nested service and permission-set references. The default representation uses UUIDs. May be combined with other Prefer preferences (e.g. return=minimal, reference-id=canonical); unrecognized preferences are ignored.

Responses

Response samples

Content type
application/json
{
  • "items": [
    ]
}

Get permission set by ID

Authorizations:
PreAuthProxy
path Parameters
permission-set-id
required
string
Examples:
  • a1b2c3d4-e5f6-7890-abcd-ef1234567890 -
  • github-read -

UUID or canonical identifier of the permission set

header Parameters
Prefer
string
Example: reference-id=canonical

Request canonical rendering of nested service and permission-set references. The default representation uses UUIDs. May be combined with other Prefer preferences (e.g. return=minimal, reference-id=canonical); unrecognized preferences are ignored.

Responses

Response samples

Content type
application/json
{
  • "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  • "canonical_id": "github-read",
  • "name": "GitHub Read Access",
  • "description": "Read repository contents and user profile from GitHub",
  • "service_scopes": [
    ],
  • "created_at": "2026-03-25T12:00:00Z",
  • "updated_at": "2026-03-25T12:00:00Z"
}

Replace a permission set

Fully replaces a permission set's name, description, and service_scopes. All fields are required (PUT semantics — full replacement).

Note: Changing service_scopes takes effect immediately; the next token exchange for any grant referencing this set will use the updated scopes (cache TTL ≤ 60s delay).

Authorizations:
PreAuthProxy
path Parameters
permission-set-id
required
string
Examples:
  • a1b2c3d4-e5f6-7890-abcd-ef1234567890 -
  • github-read -

UUID or canonical identifier of the permission set

Request Body schema: application/json
required
canonical_id
string or null [ 1 .. 128 ] characters ^[A-Za-z0-9._-]+$
name
required
string <= 255 characters

Unique human-readable name for the permission set

description
required
string

Human-readable explanation of what capabilities this set grants

required
Array of objects (ServiceScope) non-empty

One or more service/scope entries covered by this permission set

Responses

Request samples

Content type
application/json
{
  • "canonical_id": "github-read",
  • "name": "GitHub Read Access",
  • "description": "Read repository contents and user profile from GitHub",
  • "service_scopes": [
    ]
}

Response samples

Content type
application/json
{
  • "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  • "canonical_id": "github-read",
  • "name": "GitHub Read Access",
  • "description": "Read repository contents and user profile from GitHub",
  • "service_scopes": [
    ],
  • "created_at": "2026-03-25T12:00:00Z",
  • "updated_at": "2026-03-25T12:00:00Z"
}

Delete a permission set

Deletes a permission set by ID.

Rejected with 409 Conflict if any agent's permission_sets list references this ID, or if any active user grant references this permission set. Admins must remove the permission set from all agents and revoke all active grants referencing it before deletion.

Irreversible: This operation cannot be undone.

Authorizations:
PreAuthProxy
path Parameters
permission-set-id
required
string
Examples:
  • a1b2c3d4-e5f6-7890-abcd-ef1234567890 -
  • github-read -

UUID or canonical identifier of the permission set

Responses

Response samples

Content type
application/json
{
  • "error": "validation failed",
  • "message": "display_name exceeds 255 characters (got 300)"
}

Client Credentials

Broker-issued client credential management for agents

Generate or rotate broker-issued client credentials for an agent

Generate new broker-issued client credentials for an agent, or rotate existing credentials. This allows the broker to act as an OAuth2 authorization server and authenticate agents directly.

Runtime usage: Agents use the client_id returned here as client_id at the /oauth2/token endpoint. The value is the agent's UUID.

First Generation (no existing credentials):

  • Returns 201 Created with new client_id (metadata) and client_secret
  • The client_secret is only returned in this response — store it securely

Rotation (existing credentials):

  • Returns 200 OK with new credentials and previous_invalidated_at timestamp
  • Previous credentials are immediately invalidated
  • Active tokens issued with previous credentials remain valid until expiry
Authorizations:
PreAuthProxy
path Parameters
agent-id
required
string
Examples:
  • 550e8400-e29b-41d4-a716-446655440000 -
  • research-agent -

UUID or canonical identifier of the agent

Responses

Response samples

Content type
application/json
{
  • "client_id": "550e8400-e29b-41d4-a716-446655440000",
  • "client_secret": "brk_sec_q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2",
  • "created_at": "2025-12-19T15:45:00Z",
  • "previous_invalidated_at": "2025-12-19T15:45:00Z"
}

Get credential metadata (never returns secret)

Retrieve metadata about an agent's broker-issued client credentials.

Security: The client_secret is never returned by this endpoint. Only the client_id and timestamps are returned.

Returns 404 Not Found if no credentials have been generated for the agent.

Authorizations:
PreAuthProxy
path Parameters
agent-id
required
string
Examples:
  • 550e8400-e29b-41d4-a716-446655440000 -
  • research-agent -

UUID or canonical identifier of the agent

Responses

Response samples

Content type
application/json
{
  • "client_id": "550e8400-e29b-41d4-a716-446655440000",
  • "created_at": "2025-12-19T10:30:00Z",
  • "rotated_at": "2025-12-19T15:45:00Z"
}

Revoke broker-issued credentials

Revoke an agent's broker-issued client credentials.

After revocation, the agent can no longer authenticate using these credentials. Active tokens issued with these credentials remain valid until expiry.

Irreversible: New credentials must be generated via POST after revocation.

Authorizations:
PreAuthProxy
path Parameters
agent-id
required
string
Examples:
  • 550e8400-e29b-41d4-a716-446655440000 -
  • research-agent -

UUID or canonical identifier of the agent

Responses

Response samples

Content type
application/json
{
  • "error": "invalid request",
  • "message": "agent ID must be a valid UUID"
}

Signing Keys

OAuth2 server signing key management

Add a new signing key

Generate a new signing key for the broker's OAuth2 server. The new key is marked as is_current: true but does not start signing tokens until activates_at has passed (grace period = 2 × JWKS Cache-Control: max-age value, currently 600 s). During this window the key is already present in the JWKS response, so every client cache will have learned about it before the first token signed with it appears.

Algorithm Support:

  • ES256: ECDSA using P-256 curve and SHA-256 (default, only supported algorithm)

Key Lifecycle:

  • New key is immediately published to GET /oauth2/jwks.json
  • New key starts signing tokens only after activates_at (now + 600 s)
  • Previous current key continues signing during the grace period
  • Private key material is never exposed via the API
Authorizations:
PreAuthProxy
Request Body schema: application/json
optional
algorithm
string
Default: "ES256"
Value: "ES256"

Signing algorithm for the new key.

  • ES256: ECDSA using P-256 curve and SHA-256 (default, only supported algorithm)

Responses

Request samples

Content type
application/json
Example
{ }

Response samples

Content type
application/json
{
  • "kid": "key-2025-12-19-001",
  • "algorithm": "ES256",
  • "is_current": true,
  • "activates_at": "2025-12-19T10:40:00Z",
  • "created_at": "2025-12-19T10:30:00Z"
}

List active signing keys (no private material)

Retrieve all active signing keys for the broker's OAuth2 server.

Security: Private key material is never included in the response. Only public metadata (kid, algorithm, status, timestamps) is returned.

Keys are returned in creation order (newest first).

Authorizations:
PreAuthProxy

Responses

Response samples

Content type
application/json
Example
{
  • "items": [
    ]
}

Promote signing key to current

Promote an existing signing key to be the current signing key. The current key is used for signing new tokens.

Behavior:

  • The specified key becomes is_current: true
  • The previous current key is set to is_current: false
  • Previous key remains active for token verification
Authorizations:
PreAuthProxy
path Parameters
kid
required
string
Example: key-2025-12-19-001

Key identifier of the signing key

Responses

Response samples

Content type
application/json
{
  • "kid": "key-2025-12-01-001",
  • "algorithm": "ES256",
  • "is_current": true,
  • "created_at": "2025-12-01T09:00:00Z"
}

Remove signing key (soft delete)

Remove a signing key from the active key set.

Soft Delete: The key is deactivated but retained for audit purposes. Tokens previously signed with this key can no longer be verified.

Constraints:

  • Cannot delete the last remaining signing key (returns 409 Conflict)
  • Cannot delete the current signing key without first promoting another key
Authorizations:
PreAuthProxy
path Parameters
kid
required
string
Example: key-2025-12-19-001

Key identifier of the signing key

Responses

Response samples

Content type
application/json
{
  • "error": "not found",
  • "message": "Signing key with kid 'key-unknown' does not exist"
}