The Admin Server provides full CRUD operations for managing:
external_id identifies at most one agent. Comparison is exact and case-sensitive.POST /api/agents and PUT /api/agents/{agent-id} return 409 conflict when another
agent holds the resulting external ID, and 400 validation failed for empty, overlong,
invalid UTF-8 or NUL-containing values.PUT /api/agents?external_id= creates or updates the agent holding that external ID.GET /api/agents?external_id= returns [] or a one-element array.Every Admin Agent response (POST, collection PUT, ID-addressed PUT,
single GET, and list/filter GET) returns client_uris in ascending Go string
byte order. URI spelling, other collection ordering and empty-field omission
are unchanged. Stored order is irrelevant; equal-URI-set collection PUT replay does not write.
Every Admin Agent created_at and updated_at keeps the whole-second UTC
RFC 3339 presentation of Admin API 2.1.0. Collection PUT creation sets both
stored times to the current time. An actual reconcile update preserves
created_at and sets updated_at to the current time, as POST and ID-addressed
PUT do. Two changes within one second may therefore present the same
updated_at; it is not a revision or ETag. No-op replay preserves stored times
and writes nothing.
The Agentic Identity Broker uses a dual-port HTTP server architecture:
All admin operations require authentication at a trusted reverse proxy (oauth2-proxy, nginx, or an API gateway). The proxy must authenticate the caller and enforce administrator privilege before the request reaches the admin server. The broker does not identify administrators. Keep port 14000 internal and remove client-supplied identity headers at the proxy.
Configure authentication separately for the admin server:
server.admin.authentication.preauth.principal_header_name
explicitly. The broker reads the principal from that proxy-supplied header.
There is no global default principal header.server.admin.authentication.jwt. With verification: jwks
(default), set jwks_uri. The broker verifies the signature and requires exp.
With verification: none, a trusted gateway sets an unsigned JWT after it
authenticates the operator and removes client-supplied copies. Do not set
jwks_uri in this mode. The default header is Authorization with Bearer
stripped. header_name can select another header, such as X-Userinfo.
A missing or invalid JWT supplies no broker principal. The broker ignores
the plain principal header. The sweep returns 500 server_misconfiguration
without an operator principal. The proxy must reject unauthorized admin
requests before forwarding.The proxy enforces administrator privilege in both modes. The health endpoint is public and does not require authentication.
All /api requests must use the Host authority configured by
server.admin.public_url. Hostname comparison is case-insensitive; the
scheme's default port may be omitted. Forwarded Host headers are ignored.
Reverse proxies must preserve the configured public Host.
Unsafe cross-origin browser requests are rejected using Go's
http.CrossOriginProtection, even when the origin is permitted by CORS.
POST, PUT, and PATCH requests require Content-Type: application/json,
including actions with no request body. Other requests carrying a body
also require JSON. Media-type parameters such as charset=utf-8 are accepted.
These checks return 403 Forbidden for an unrecognized Host or a
cross-origin mutation, and 415 Unsupported Media Type for a missing,
malformed, or non-JSON Content-Type. Boundary rejection bodies are plain
text. /health is not subject to these checks.
client_secret as "REDACTED"none) and both CIMD service modes omit client_secret because they store no shared secretclient_id and client_secret, including redaction placeholderscredential_source: stored | filesystem/api/services routesclient_registration selects the source of the client identifier. It is independent of
token_endpoint_auth_method, which selects token-endpoint authentication. Every service
response reports static or cimd.
static with absent or null authentication is static confidential. static with none is static public.cimd with private_key_jwt is CIMD confidential. cimd with none is CIMD public.cimd. Discovery-selected DCR reports static.
discovery.client_method remains the authoritative discovery method. Discovery never selects CIMD public.cimd for private_key_jwt, and static otherwise.
Omission never infers CIMD public. Explicit null, empty, and unknown registrations return 400.static with private_key_jwt, cimd with absent or null authentication, and cimd with
Google flavor or filesystem credentials return 400 before discovery or provider traffic.discovery.resource_url must omit client_registration. Presence returns 400 before discovery traffic.client_id or client_secret. CIMD public needs no CIMD client-authentication key.cimd for private_key_jwt, and static otherwise.redirect_uris, which also accept native-app private-use scheme URIs (see the redirect_uris schema)Direct authorization-server metadata discovery keeps its existing metadata_url behavior.
Protected-resource discovery uses discovery.resource_url with enable_discovery: true.
The broker validates the resource and issuer, then selects hosted CIMD or DCR.
The authenticated discovery-status resource reads stored status without contacting the provider.
DCR needs a non-blank deployment-wide third_party_oauth2.client_name; manual and CIMD modes do not.
Discovery and registration failures return safe ErrorResponse.message codes only.
They do not return provider bodies, URL queries, secrets, assertions, or tokens.
A 400 discovery failure uses one of these codes:
resource_metadata_not_found, resource_metadata_unavailable,
resource_metadata_invalid, resource_mismatch, authorization_server_missing,
issuer_selection_required, issuer_not_advertised,
authorization_server_metadata_not_found, authorization_server_metadata_unavailable,
authorization_server_metadata_invalid, issuer_mismatch,
unsafe_destination, response_too_large.
A 400 client-registration failure uses no_compatible_client_method,
cimd_unavailable, client_name_unconfigured, client_registration_rejected,
client_registration_invalid, or client_method_changed.
timeout returns 504; duplicate_client_identity and
issuer_change_requires_no_sessions return 409. Local storage or encryption
failures return 500 without a failure code. Only issuer_selection_required
adds the validated authorization_servers list to its authenticated error response.
By default, every HTTP response from this API includes the additive W3C
traceresponse response header.
<trace-id> field is the request correlation identifier operators can use to find matching logs.request_context.trace.response_enabled.Handler error responses follow the ErrorResponse schema with appropriate HTTP status codes. Browser boundary rejections use plain-text bodies as described above.
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 requests503 Service Unavailable: Server is starting, shutting down, or unhealthyHealth States:
healthy: Server is operational and processing requests normallystarting: Server is initializing (binding to port, setting up routes)shutting_down: Graceful shutdown in progress, completing in-flight requestsunhealthy: Server encountered an error and requires restart{- "status": "healthy",
- "timestamp": "2025-12-19T10:30:00Z",
- "uptime_seconds": 3600
}Retrieve registered agents. Without external_id, return all agents.
With one external_id, return the exact, case-sensitive match, if any.
External IDs are unique, so the array contains zero or one agent.
Do not trim, normalize, or interpret the value as a pattern. The filter
does not match agent IDs, canonical IDs, or client IDs.
Percent-encode reserved characters in the value, such as &, +, and ;.
For example, send urn:example:ai-registry:agent:7f3a9c as
urn%3Aexample%3Aai-registry%3Aagent%3A7f3a9c.
Invalid filters return 400 with error: invalid external_id.
This includes empty or repeated values, invalid UTF-8, NUL, more than
255 Unicode code points, malformed percent-encoding, and an unencoded ;.
Unknown parameters and malformed query parts outside external_id
retain their existing handling.
Returns a direct array of agent objects (no envelope), in no guaranteed order.
| external_id | string [ 1 .. 255 ] characters Example: external_id=urn:example:ai-registry:agent:7f3a9c Exact, case-sensitive external governance ID. Percent-encode reserved characters. |
| 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.
|
[- {
- "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": [
- {
- "permission_set_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
- "requirement_type": "mandatory"
}
], - "created_at": "2025-12-01T10:00:00Z",
- "updated_at": "2025-12-01T10:00:00Z"
}, - {
- "id": "660e8400-e29b-41d4-a716-446655440001",
- "client_id": "agent-data-analyst",
- "external_id": "gov-sys-12345",
- "display_name": "Data Analyst",
- "description": "Analyzes datasets and generates insights",
- "permission_sets": [
- {
- "permission_set_id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
- "requirement_type": "mandatory"
}
], - "created_at": "2025-12-05T14:30:00Z",
- "updated_at": "2025-12-10T09:15:00Z"
}
]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:
multi_agent_client.enabled = false (default): client_id must be unique
across all agents. Returns 409 Conflict if a duplicate client_id is detected.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 = falsedisplay_name: Required, max 255 charactersdescription: Required, max 1000 charactersredirect_uris entries follow the redirect_uris schema rulesexternal_id uniqueness: When supplied, external_id must be valid UTF-8 text with
1–255 Unicode code points and no NUL character, and must not
be held by another agent. An empty string returns 400 validation failed. A held value
returns 409 conflict with message external_id is already held by another agent.
Omit external_id or send null for agents without one; any number of agents may omit it.
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.
| 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 [ 1 .. 255 ] characters Optional external governance identifier; valid UTF-8 with 1–255 Unicode code points, no NUL, and globally unique when set. Collection PUT requires a supplied value to equal its selector and rejects null. |
| 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.
Each entry is an |
| 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 |
{- "client_id": "agent-simple-assistant",
- "display_name": "Simple Assistant",
- "description": "A basic AI assistant for general tasks",
- "permission_sets": [
- {
- "permission_set_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
- "requirement_type": "mandatory"
}
]
}{- "id": "550e8400-e29b-41d4-a716-446655440000",
- "client_id": "agent-research-assistant",
- "external_id": "gov-sys-12345",
- "display_name": "Research Assistant",
- "description": "AI assistant that helps with academic research",
- "permission_sets": [
- {
- "permission_set_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
- "requirement_type": "mandatory"
}
], - "created_at": "2025-12-19T10:30:00Z",
- "updated_at": "2025-12-19T10:30:00Z"
}Idempotently reconcile the agent identified by an external governance ID.
external_id: create one and return 201 Created with Location.200 OK. The selector never matches
agent IDs, canonical IDs, or client IDs.200 with the
unchanged representation, including updated_at. Nothing is written.If-Match, concurrent different definitions are last-writer-wins; each
successful request applies its complete definition.Selector: exactly one external_id query parameter, 1–255 Unicode code points,
valid UTF-8, no NUL, valid percent-encoding, and no unencoded ;. Percent-encode &,
+, and ;. Otherwise 400 invalid external_id.
Body: AgentCreateRequest. Omitted external_id takes the selector. A supplied
external_id must equal the decoded selector; a different value, "", or null
returns 400 invalid external_id.
Update-branch field policy (FR-012):
| Fields | Omitted | null |
Value |
|---|---|---|---|
client_id |
preserved | 400 validation failed |
replaced |
canonical_id |
preserved | removed | replaced |
governance_url, user_documentation_url, agent_interface_url |
removed | removed | replaced |
service_requirements, redirect_uris, allowed_scopes, client_uris |
emptied | emptied | replaced |
display_name, description, permission_sets |
400 |
400 |
replaced |
On creation, omitted optional fields are absent or empty and no client_id is generated.
Grants and other relationships of an updated agent are not changed. To clear an existing
client_id, use PUT /api/agents/{agent-id} with client_id: null.
Invalid definitions, attributes, and references on either branch return 400
with the existing validation failed envelope. Canonical-ID conflicts,
configuration-dependent client_id conflicts (multi_agent_client.enabled),
and client-URI identity conflicts return 409 conflict on both branches.
Failed requests change no agent. Agent ordering and timestamps follow
"Stable Agent Response Presentation" above on create, update, and replay.
| external_id required | string [ 1 .. 255 ] characters Example: external_id=urn:example:ai-registry:agent:7f3a9c Exact, case-sensitive external governance ID that selects the agent. Percent-encode reserved characters. |
| 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.
|
| 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 [ 1 .. 255 ] characters Optional external governance identifier; valid UTF-8 with 1–255 Unicode code points, no NUL, and globally unique when set. Collection PUT requires a supplied value to equal its selector and rejects null. |
| 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.
Each entry is an |
| 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 |
{- "canonical_id": "research-assistant",
- "external_id": "urn:example:ai-registry:agent:7f3a9c",
- "display_name": "Research Assistant",
- "description": "Helps with academic research",
- "permission_sets": [
- {
- "permission_set_id": "github-read",
- "requirement_type": "mandatory"
}
]
}{- "id": "550e8400-e29b-41d4-a716-446655440000",
- "canonical_id": "research-assistant",
- "external_id": "urn:example:ai-registry:agent:7f3a9c",
- "display_name": "Research Assistant v2",
- "description": "Helps with academic research",
- "permission_sets": [
- {
- "permission_set_id": "github-read",
- "requirement_type": "mandatory"
}
], - "created_at": "2026-10-30T08:00:00Z",
- "updated_at": "2026-10-30T09:00:00Z"
}Retrieve detailed information about a specific agent.
Returns the complete agent configuration including all optional fields.
| agent-id required | string Examples:
UUID or canonical identifier of the agent |
| 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.
|
{- "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": [
- {
- "permission_set_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
- "requirement_type": "mandatory"
}
], - "created_at": "2025-12-19T10:30:00Z",
- "updated_at": "2025-12-19T10:30:00Z"
}Update configuration for an existing agent.
When supplied, external_id must be non-empty and must not be held by another agent
(400 validation failed / 409 conflict). Retaining its own external ID is not a
conflict. Canonical-ID, client-ID, and client-URI conflicts also return 409.
Update Semantics:
external_id, governance_url, user_documentation_url, agent_interface_url, service_requirements, redirect_uris, allowed_scopes, and client_uris are clearedcanonical_id and client_id are the exceptions: omitted preserves the existing value, and explicit null clears itcreated_at timestamp is preservedupdated_at timestamp is set to current timeclient_id uniqueness depends on configuration:
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.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| agent-id required | string Examples:
UUID or canonical identifier of the agent |
| 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:
Agents without a client_id cannot participate in proxy-mode OAuth2 flows. |
| external_id | string or null [ 1 .. 255 ] characters Optional external governance identifier; valid UTF-8 with 1–255 Unicode code points, no NUL, and globally unique when set. Omission or null clears it; retaining the current agent's value is not a conflict. |
| 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.
Each entry is an |
| 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 |
{- "client_id": "agent-research-assistant",
- "display_name": "Advanced Research Assistant",
- "description": "AI assistant that helps with academic research",
- "permission_sets": [
- {
- "permission_set_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
- "requirement_type": "mandatory"
}
]
}{- "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": [
- {
- "permission_set_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
- "requirement_type": "mandatory"
}
], - "created_at": "2025-12-19T10:30:00Z",
- "updated_at": "2025-12-19T15:45:00Z"
}Remove an agent from the system.
Cascade Behavior:
Irreversible: This operation cannot be undone
| agent-id required | string Examples:
UUID or canonical identifier of the agent |
{- "error": "agent ID is required"
}Retrieve a list of all configured third-party OAuth2 services.
Returns a direct array of service objects (no envelope).
Every object reports credential_source and client_registration.
Static confidential services return their client ID and "REDACTED" secret.
Static public, CIMD, and DCR services omit the secret. Filesystem services omit inline credentials.
Listing never reads files or returns paths or file values.
| 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.
|
[- {
- "id": "770e8400-e29b-41d4-a716-446655440002",
- "display_name": "GitHub Production",
- "credential_source": "stored",
- "client_registration": "static",
- "oauth2_flavor": "github",
- "client_id": "Iv1.1234567890abcdef",
- "client_secret": "REDACTED",
- "token_endpoint_auth_method": null,
- "discovery": {
- "enable_discovery": true,
- "authorization_param_resource_strategy": null
}, - "endpoints": {
}, - "scopes": [
- {
- "scope_value": "repo",
- "description": "Full control of private repositories"
}, - {
- "scope_value": "read:org",
- "description": "Read organization membership"
}
], - "created_at": "2025-12-01T09:00:00Z",
- "updated_at": "2025-12-15T14:30:00Z"
}, - {
- "id": "880e8400-e29b-41d4-a716-446655440003",
- "display_name": "Google Cloud",
- "credential_source": "stored",
- "client_registration": "static",
- "oauth2_flavor": "google",
- "client_id": "123456789-abcdef.apps.googleusercontent.com",
- "client_secret": "REDACTED",
- "token_endpoint_auth_method": null,
- "discovery": {
- "enable_discovery": true,
- "authorization_param_resource_strategy": null
}, - "endpoints": {
}, - "scopes": [
- {
- "description": "View and download Google Drive files"
}
], - "created_at": "2025-12-05T11:20:00Z",
- "updated_at": "2025-12-05T11:20:00Z"
}, - {
- "id": "990e8400-e29b-41d4-a716-446655440004",
- "canonical_id": "zalando-platform",
- "display_name": "Zalando Platform",
- "credential_source": "filesystem",
- "client_registration": "static",
- "oauth2_flavor": "standard",
- "token_endpoint_auth_method": null,
- "discovery": {
- "enable_discovery": false
}, - "endpoints": {
}, - "created_at": "2026-10-08T09:00:00Z",
- "updated_at": "2026-10-08T09:00:00Z"
}
]Configure a new third-party OAuth2 service provider.
Validation Rules:
display_name: Required, max 255 characterscredential_source: stored or filesystem; omission selects stored; explicit null and unknown values are invalidclient_registration: Optional static or cimd. Omission selects cimd for private_key_jwt and static otherwise. Explicit null, empty, or unknown values return 400client_id: Required and unique under existing validation, except Google derives it and CIMD generates it; discovery selects the client identityclient_secret: Required for static confidential services. Static public and both CIMD modes accept omitted, null, or empty secret inputissuer_uri: Required and HTTPS, subject to existing Google service-account rules; optional for protected-resource discovery with one issuerscopes: Optional. Omit it or provide an empty array when the provider does not use OAuth2 scopes.Filesystem registration never reads files or requires an available binding. Paths belong only to operator configuration and cannot be supplied through this API. Every successful response reports the selected source. Filesystem responses omit both inline fields.
CIMD modes: client_registration: cimd with private_key_jwt is confidential.
With none, it is public and needs no CIMD client-authentication key.
Both require omitted or null client_id and omitted, null, or empty client_secret.
The broker rejects a non-empty caller value, Google flavor, or filesystem source with
400 before provider traffic. It assigns the HTTPS client identifier URL after it creates the service ID.
static with private_key_jwt, or cimd with absent or null authentication, returns 400.
Direct metadata discovery: Without resource_url, metadata_url can select an
authorization-server document. The existing manual-endpoint fallback remains unchanged.
Protected-resource discovery: Set discovery.resource_url with
enable_discovery: true. Omit client_registration, manual endpoints, client credentials,
metadata_url, and token_endpoint_auth_method. A supplied registration returns 400
before discovery traffic. An issuer selection is optional for one issuer.
The broker derives authorization_params.resource unless the request supplies an
explicit value. A selected DCR client needs a non-blank broker client name from
deployment configuration, not the service display name. Failures do not create a service.
Security: Static and DCR confidential secrets are encrypted before storage. A DCR secret never appears in an Admin API response.
| oauth2_flavor | string Default: "standard" Enum: "standard" "google" "github" OAuth2 authentication variant. Defaults to
|
| client_id required | string or null non-empty OAuth2 client_id for this service. In stored mode, manual static For protected-resource discovery, this property must be omitted, null, or empty. |
| client_registration | string Enum: "static" "cimd" Optional on create. Omission resolves to |
| token_endpoint_auth_method | string or null Enum: "none" "private_key_jwt" null Client authentication method for the upstream token endpoint. Omit it or send When When With |
| client_secret required | string or null non-empty Authentication credential for a static confidential service. The content depends on
SECURITY: Static confidential-service secrets are encrypted at rest using AES-256-GCM
and return only as For manual stored services, an omitted or null |
required | object |
| credential_source | string Default: "stored" Enum: "stored" "filesystem" Omission selects stored. Null is invalid. Filesystem rejects inline fields and excluded authentication modes. |
| 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 |
| issuer_uri | string <uri> OAuth2 issuer URI. Required for manual standard services and HTTPS. Optional for protected-resource
discovery with one issuer. If the resource advertises several issuers, the
administrator must select an identical |
object (OAuth2EndpointsRequest) OAuth2 endpoints configuration. Required when Each supplied | |
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 Provider parameters. For protected-resource discovery, |
{- "display_name": "GitHub Production",
- "client_id": "Iv1.1234567890abcdef",
- "client_secret": "ghp_secretkey1234567890abcdef",
- "discovery": {
- "enable_discovery": true
}, - "scopes": [
- {
- "scope_value": "repo",
- "description": "Full control of private repositories"
}, - {
- "scope_value": "read:org",
- "description": "Read organization membership"
}, - {
- "scope_value": "user:email",
- "description": "Read user email addresses"
}
]
}{- "id": "770e8400-e29b-41d4-a716-446655440002",
- "display_name": "GitHub Production",
- "credential_source": "stored",
- "client_registration": "static",
- "oauth2_flavor": "github",
- "client_id": "Iv1.1234567890abcdef",
- "client_secret": "REDACTED",
- "token_endpoint_auth_method": null,
- "discovery": {
- "enable_discovery": true,
- "authorization_param_resource_strategy": null
}, - "endpoints": {
}, - "scopes": [
- {
- "scope_value": "repo",
- "description": "Full control of private repositories"
}, - {
- "scope_value": "read:org",
- "description": "Read organization membership"
}
], - "created_at": "2025-12-19T10:30:00Z",
- "updated_at": "2025-12-19T10:30:00Z"
}Retrieve detailed configuration for a specific OAuth2 service.
Every response reports credential_source and client_registration without reading files.
Stored responses always include client_id. Static confidential secrets return only
"REDACTED"; static public, CIMD, and DCR responses omit the secret.
Filesystem responses omit both inline credential fields, file paths, and file values.
| service-id required | string Examples:
UUID or canonical identifier of the OAuth2 service |
| 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.
|
{- "id": "770e8400-e29b-41d4-a716-446655440002",
- "display_name": "GitHub Production",
- "credential_source": "stored",
- "client_registration": "static",
- "oauth2_flavor": "github",
- "client_id": "Iv1.1234567890abcdef",
- "client_secret": "REDACTED",
- "token_endpoint_auth_method": null,
- "discovery": {
- "enable_discovery": true,
- "authorization_param_resource_strategy": null
}, - "endpoints": {
}, - "scopes": [
- {
- "scope_value": "repo",
- "description": "Full control of private repositories"
}
], - "created_at": "2025-12-19T10:30:00Z",
- "updated_at": "2025-12-19T10:30:00Z"
}Update configuration for an existing OAuth2 service.
Update Semantics:
credential_source omission preserves the current source. Explicit null and unknown selectors are invalidclient_registration resolves to cimd for private_key_jwt and static otherwise, not to the old value. Explicit null, empty, or unknown values return 400client_registration: cimd. Without it, PUT resolves to static and fails without an operator client_idtoken_endpoint_auth_method is evaluated from the complete request. Omitted or null means shared-secret authentication: stored requires an explicit non-empty secret, while filesystem forbids inline credentials. Protected-resource refresh retains the broker-selected method and credentialstoken_endpoint_auth_method: private_key_jwt requires client_id to be omitted or null and client_secret to be omitted, null, or empty. A valid replacement removes any prior static secret and assigns the stable broker-generated HTTPS Client ID Metadata Document URL.static to cimd replaces the operator client ID and removes a stored secret only after validation. Switching back requires an operator client_id. Static confidential also requires a new secretstatic makes the hosted document return 404. Providers can cache the previous document for up to 300 seconds. The broker never falls back to another token authentication methodtoken_endpoint_auth_method: none removes the stored credential.created_at timestamp is preservedupdated_at timestamp is set to current timeSource Transitions:
filesystem, a valid resulting canonical ID, and neither inline fieldstored and explicitly supplied non-empty client_id and client_secretSecret Rotation:
client_secret to rotate stored static confidential-service credentialsDiscovery Re-run:
enable_discovery: true, endpoints are re-fetchedProtected-resource refresh: An omitted issuer_uri retains the active issuer
only if fresh resource metadata still advertises it. A different issuer requires
explicit selection and zero user sessions. An effective authorization_params.resource
change also requires zero user sessions, even when the issuer stays the same.
Keep the client method and the exact token authentication method. Preserve the
client ID and secret for an unchanged issuer. For a discovery-backed refresh,
omitted authorization_params keeps the map and its explicit or derived source.
A replacement without resource restores the derived resource. On replacement
with manual configuration, omission keeps the parameter map but clears the
discovery source and resource source marker. For a manual replacement, an explicit
empty map clears all parameters. A discovery-backed rejection writes a safe
failure-only status without changing the active service ETag. A manual conversion
rejected for an audience change writes no discovery status.
A request with discovery.resource_url must omit client_registration. Presence
returns 400 before discovery traffic. Hosted CIMD reports cimd. DCR reports
static. The selected discovery.client_method remains authoritative.
Security: Static confidential-service client_secret values are redacted in responses.
Static public, CIMD, and DCR responses omit the property. Filesystem responses omit inline
credentials, paths, and file values. Every response reports credential_source and client_registration.
protected_resources omitted or null: preserves the current protected-resource setprotected_resources present (including []): replaces the entire set and requires If-Match| service-id required | string Examples:
UUID or canonical identifier of the OAuth2 service |
| If-Match | string Required when a service update request includes |
| oauth2_flavor | string Default: "standard" Enum: "standard" "google" "github" OAuth2 authentication variant. Defaults to
|
| client_id required | string or null non-empty OAuth2 client_id for this service. In stored mode, manual static For protected-resource discovery, this property must be omitted, null, or empty. |
| client_registration | string Enum: "static" "cimd" Optional on full-replacement PUT. Omission resolves to |
| token_endpoint_auth_method | string or null Enum: "none" "private_key_jwt" null Client authentication method for the upstream token endpoint. This request retains the
existing full-replacement semantics: the method is evaluated from the complete replacement
request. Omit this property, or send When CIMD confidential and CIMD public keep the same client identifier URL when switching.
A switch from With |
| client_secret required | string or null non-empty Authentication credential for a static confidential service. Provide a new value to rotate. The content depends on
SECURITY: Static confidential-service secrets are encrypted at rest and never returned in responses. For manual stored services, an omitted or null authentication method requires a new non-empty static secret. Manual public and CIMD modes accept omitted, null, or empty values. Protected-resource updates also require an omitted, null, or empty value; the broker keeps the stored DCR credential when eligible. Filesystem mode forbids this property, including null or empty input. Returning to stored requires an explicit non-empty secret. |
required | object |
| credential_source required | string Enum: "stored" "filesystem" Omission preserves the existing source. Explicit null is invalid. No creation default applies to PUT. |
| canonical_id | string or null [ 1 .. 128 ] characters ^[A-Za-z0-9._-]+$ Omission preserves the current ID. Null clears it only in stored mode. Filesystem mode requires a valid resulting ID. |
| display_name required | string [ 1 .. 255 ] characters Human-readable name for the service |
| issuer_uri | string <uri> OAuth2 issuer URI. Required for manual standard services and HTTPS. For protected-resource discovery, omission keeps the active issuer if fresh metadata advertises it. A different issuer needs explicit selection and zero user sessions. Google retains its existing service-account rules. |
object (OAuth2EndpointsRequest) OAuth2 endpoints configuration. Required when Each supplied | |
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 |
object Provider parameters. Omission preserves the map, including on replacement with
manual configuration. For a manual replacement, an explicit empty object clears
the map. For discovery-backed services, a replacement with |
{- "display_name": "GitHub Production",
- "client_id": "Iv1.1234567890abcdef",
- "client_secret": "ghp_newsecretkey9876543210zyxwvu",
- "discovery": {
- "enable_discovery": true
}, - "scopes": [
- {
- "scope_value": "repo",
- "description": "Full control of private repositories"
}, - {
- "scope_value": "read:org",
- "description": "Read organization membership"
}
]
}{- "id": "770e8400-e29b-41d4-a716-446655440002",
- "display_name": "GitHub Production",
- "credential_source": "stored",
- "client_registration": "static",
- "oauth2_flavor": "github",
- "client_id": "Iv1.1234567890abcdef",
- "client_secret": "REDACTED",
- "token_endpoint_auth_method": null,
- "discovery": {
- "enable_discovery": true,
- "authorization_param_resource_strategy": null
}, - "endpoints": {
}, - "scopes": [
- {
- "scope_value": "repo",
- "description": "Full control of private repositories"
}, - {
- "scope_value": "read:org",
- "description": "Read organization membership"
}, - {
- "scope_value": "workflow",
- "description": "Update GitHub Actions workflows"
}
], - "created_at": "2025-12-19T10:30:00Z",
- "updated_at": "2025-12-19T16:00:00Z"
}Remove an OAuth2 service from the system.
Referential Integrity Check:
Irreversible: This operation cannot be undone
| service-id required | string Examples:
UUID or canonical identifier of the OAuth2 service |
{- "error": "client ID is required"
}Read stored status without contacting a resource or authorization server.
A missing operator principal returns 401 before the service is read.
A failed refresh keeps the last successful issuer, client method, and resource URL.
Manual services return not_applicable and null discovery fields.
| service-id required | string Examples:
UUID or canonical identifier of the OAuth2 service |
{- "status": "ready",
- "client_method": "dcr",
- "last_attempt_at": "2026-10-06T10:00:00Z",
- "last_success_at": "2026-10-06T10:00:00Z",
- "failure_reason": null
}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.
| service-id required | string Examples:
UUID or canonical identifier of the OAuth2 service |
| resource_uri required | string <uri> Absolute resource URI (scheme and host required), normalized by trailing-slash trim. |
{
}{
}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.
| service-id required | string Examples:
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 ( |
{
}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.
| service-id required | string Examples:
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 required | string <uri> Absolute target URI (scheme and host required), normalized by trailing-slash trim. |
{
}{
}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.
| service-id required | string Examples:
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 ( |
{
}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)service_id in service_scopes must reference an existing service (400)scopes list may be empty for a scope-less service; supplied values
must be non-empty (400)| 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 |
{- "canonical_id": "github-read",
- "name": "GitHub Read Access",
- "description": "Read repository contents and user profile from GitHub",
- "service_scopes": [
- {
- "service_id": "string",
- "scopes": [
- "repo:read",
- "user:email"
], - "requirement_type": "mandatory"
}
]
}{- "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": [
- {
- "service_id": "string",
- "scopes": [
- "repo:read",
- "user:email"
], - "requirement_type": "mandatory"
}
], - "created_at": "2026-03-25T12:00:00Z",
- "updated_at": "2026-03-25T12:00:00Z"
}Returns all permission sets. Optionally filter by service ID to find all permission sets that include scopes for a specific third-party service.
| service_id | string UUID or canonical identifier of the service used to filter permission sets |
| 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.
|
{- "items": [
- {
- "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": [
- {
- "service_id": "string",
- "scopes": [
- "repo:read",
- "user:email"
], - "requirement_type": "mandatory"
}
], - "created_at": "2026-03-25T12:00:00Z",
- "updated_at": "2026-03-25T12:00:00Z"
}
]
}| permission-set-id required | string Examples:
UUID or canonical identifier of the permission set |
| 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.
|
{- "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": [
- {
- "service_id": "string",
- "scopes": [
- "repo:read",
- "user:email"
], - "requirement_type": "mandatory"
}
], - "created_at": "2026-03-25T12:00:00Z",
- "updated_at": "2026-03-25T12:00:00Z"
}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).
| permission-set-id required | string Examples:
UUID or canonical identifier of the permission set |
| 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 |
{- "canonical_id": "github-read",
- "name": "GitHub Read Access",
- "description": "Read repository contents and user profile from GitHub",
- "service_scopes": [
- {
- "service_id": "string",
- "scopes": [
- "repo:read",
- "user:email"
], - "requirement_type": "mandatory"
}
]
}{- "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": [
- {
- "service_id": "string",
- "scopes": [
- "repo:read",
- "user:email"
], - "requirement_type": "mandatory"
}
], - "created_at": "2026-03-25T12:00:00Z",
- "updated_at": "2026-03-25T12:00:00Z"
}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.
| permission-set-id required | string Examples:
UUID or canonical identifier of the permission set |
{- "error": "validation failed",
- "message": "display_name exceeds 255 characters (got 300)",
}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):
201 Created with new client_id (metadata) and client_secretclient_secret is only returned in this response — store it securelyRotation (existing credentials):
200 OK with new credentials and previous_invalidated_at timestamp| agent-id required | string Examples:
UUID or canonical identifier of the agent |
{- "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"
}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.
| agent-id required | string Examples:
UUID or canonical identifier of the agent |
{- "client_id": "550e8400-e29b-41d4-a716-446655440000",
- "created_at": "2025-12-19T10:30:00Z",
- "rotated_at": "2025-12-19T15:45:00Z"
}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.
| agent-id required | string Examples:
UUID or canonical identifier of the agent |
{- "error": "invalid request",
- "message": "agent ID must be a valid UUID"
}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 (600 s after key preparation). This covers a 300 s
compliant JWKS cache lifetime and a 30 s rebuild budget with 270 s of margin
under healthy-service conditions. External verifiers must refresh their own
caches; publication cannot force them to learn the key.
Algorithm Support:
ES256: ECDSA using P-256 curve and SHA-256 (default, only supported algorithm)Key Lifecycle:
GET /oauth2/jwks.json after storage commitsactivates_at (key preparation + 600 s)| algorithm | string Default: "ES256" Value: "ES256" Signing algorithm for the new key.
|
{ }{- "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"
}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).
{- "items": [
- {
- "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"
}, - {
- "kid": "key-2025-12-01-001",
- "algorithm": "ES256",
- "is_current": false,
- "activates_at": "2025-12-01T09:00:00Z",
- "created_at": "2025-12-01T09:00:00Z"
}
]
}Promote an existing signing key to be the current signing key. The current key is used for signing new tokens.
Behavior:
is_current: trueis_current: false| kid required | string Example: key-2025-12-19-001 Key identifier of the signing key |
{- "kid": "key-2025-12-01-001",
- "algorithm": "ES256",
- "is_current": true,
- "created_at": "2025-12-01T09:00:00Z"
}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:
409 Conflict)| kid required | string Example: key-2025-12-19-001 Key identifier of the signing key |
{- "error": "not found",
- "message": "Signing key with kid 'key-unknown' does not exist"
}Administrative lifecycle operations for the broker-global CIMD client-authentication key set
Generate an ES256 key in the distinct broker-global CIMD client-authentication key domain.
This key signs outbound private_key_jwt client assertions only; it never signs broker-issued
access tokens.
Key Lifecycle:
| algorithm | string Default: "ES256" Value: "ES256" ES256 is the default and only accepted CIMD client-authentication key algorithm. |
{ }{- "kid": "cimd-key-2026-09-21-001",
- "algorithm": "ES256",
- "is_current": true,
- "activates_at": "2026-09-21T10:30:00Z",
- "created_at": "2026-09-21T10:30:00Z"
}Retrieve active CIMD client-authentication keys in creation order (newest first). Responses contain metadata only and never include private key bytes, PEM, ciphertext, branch-key identifiers, or client assertions.
{- "items": [
- {
- "kid": "cimd-key-2026-09-21-001",
- "algorithm": "ES256",
- "is_current": true,
- "activates_at": "2026-09-21T10:40:00Z",
- "created_at": "2026-09-21T10:30:00Z"
}, - {
- "kid": "cimd-key-2026-09-01-001",
- "algorithm": "ES256",
- "is_current": false,
- "activates_at": "2026-09-01T09:00:00Z",
- "created_at": "2026-09-01T09:00:00Z"
}
]
}Promote an existing CIMD client-authentication key to current immediately. The promoted key becomes usable to sign subsequent client assertions at promotion time. The prior key remains available for verification through the CIMD JWK Set.
| kid required | string Example: cimd-key-2026-09-21-001 Globally unique identifier of the CIMD client-authentication key |
{- "kid": "cimd-key-2026-09-01-001",
- "algorithm": "ES256",
- "is_current": true,
- "activates_at": "2026-09-21T10:45:00Z",
- "created_at": "2026-09-01T09:00:00Z"
}Remove a CIMD client-authentication key that is neither the last key, the current key, nor an effective-current key that can still sign assertions. Removed keys are no longer published in the CIMD JWK Set.
| kid required | string Example: cimd-key-2026-09-21-001 Globally unique identifier of the CIMD client-authentication key |
{- "error": "agent not found",
- "message": "Agent with ID '550e8400-e29b-41d4-a716-446655440000' does not exist"
}Refreshes every stored third-party user session whose access token expires within the
lookahead window, across all principals and services. Intended to be called on a schedule
by an external job, such as the CronJob the broker Helm chart renders when
sessionSweep.enabled is true; the broker runs no internal scheduler.
Selection: A session is a candidate when its access token has a recorded expiry at or
before now + lookahead_duration. Sessions with no access-token expiry are never
candidates. Healthy sessions outside the window are not evaluated and do not appear in any
count.
Processing: Candidates are read in pages of page_size and refreshed one at a time
using each session's stored refresh token. Newly issued tokens are encrypted before they
are stored. A candidate that another refresh already renewed, or that was deleted during
the sweep, is counted as skipped. A candidate that cannot be refreshed (no usable refresh
token, upstream error) is counted as failed. The sweep then continues and the stored
tokens are left unchanged. When the provider rejects the refresh token with a 4xx
invalid_grant (other than 429), the broker records the rejection and counts that
attempt as failed. Later sweeps exclude the session from their candidates, so it
contributes to no count and the provider is not contacted again until the user reconnects.
Dry run: With dry_run: true, candidates are classified without calling any upstream
provider and without writing. Candidates that would be refreshed are counted in
refreshed.
Concurrency: Safe to invoke concurrently on several broker replicas. Each session is refreshed under a row lock, so concurrent sweeps never refresh the same session twice and never leave a partial update. Concurrent sweeps do not divide the work between them.
Duration: The request runs until every candidate has been evaluated. The server removes its write timeout for this operation. The caller controls the overall timeout. If the client disconnects, the sweep stops after the session in progress, and sessions already refreshed stay refreshed.
Response semantics: 200 OK is returned whenever the sweep itself completes, even if
every candidate failed. 500 is returned if the sweep cannot continue because of an
infrastructure failure or the request lacks an operator principal. The response contains
only counts and never token material.
Every invocation is audit-logged with the operator principal.
All fields are optional. An empty body and {} are equivalent. The
Content-Type: application/json header is still required (see Browser Request Protection).
| lookahead_duration | string <duration> ^P(?!$)(?:\d+D)?(?:T(?=\d)(?:\d+H)?(?:\d+M)?(... ISO 8601 duration. Sessions whose access token expires within this duration from the
start of the sweep are refreshed. Only day, hour, minute, and second components are
accepted ( |
| dry_run | boolean Default: false When true, report what would be refreshed without contacting upstream providers or writing. |
| page_size | integer <int32> [ 1 .. 1000 ] Number of candidate sessions read per page. Defaults to the server-configured
|
{ }{- "refreshed": 42,
- "skipped": 3,
- "failed": 1,
- "total_evaluated": 46,
- "dry_run": false
}