Connected Apps / Dynamic Client Registration
Register OAuth 2.0 clients dynamically and manage them via the admin API.
Dynamic Client Registration
POST /oauth2/register
Register a new OAuth 2.0 client following RFC 7591. This endpoint is used by applications that need to become first-class OAuth clients within Bulwark — receiving their own client_id and client_secret — so that agents can authenticate on their behalf.
Headers
X-Bulwark-Tenant: <tenant-id>Authorization: Bearer <initial-access-token>— Optional. Required if DCR is restricted by tenant policy.
Body
{
"client_name": "Acme Data Exporter",
"redirect_uris": ["https://app.acme.com/auth/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"scope": "read:customers write:reports",
"token_endpoint_auth_method": "client_secret_basic",
"application_type": "web",
"contacts": ["[email protected]"],
"logo_uri": "https://app.acme.com/logo.png",
"client_uri": "https://app.acme.com"
}
| Field | Required | Description |
|-------|----------|-------------|
| client_name | Yes | Human-readable application name |
| redirect_uris | Yes (for authorization_code) | Allowed redirect URIs |
| grant_types | No | Defaults to ["authorization_code"]. Also supports client_credentials. |
| response_types | No | Defaults to ["code"] |
| scope | No | Requested OAuth scopes |
| token_endpoint_auth_method | No | client_secret_basic, client_secret_post, or none |
Response 201
{
"client_id": "app_01j...",
"client_secret": "cs_live_...",
"client_id_issued_at": 1743292800,
"client_secret_expires_at": 0,
"client_name": "Acme Data Exporter",
"redirect_uris": ["https://app.acme.com/auth/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"scope": "read:customers write:reports",
"token_endpoint_auth_method": "client_secret_basic",
"registration_access_token": "rat_01j...",
"registration_client_uri": "/oauth2/register/app_01j..."
}
Important: client_secret is returned only once. Store it securely.
List Clients (Admin)
GET /api/v1/oauth2/clients
Headers
Authorization: Bearer <apiKey>X-Bulwark-Tenant: <tenant-id>
Query Parameters
| Parameter | Description |
|-----------|-------------|
| limit | Results per page (default: 20, max: 100) |
| cursor | Pagination cursor |
| grant_type | Filter by grant type |
Response 200
{
"data": [
{
"client_id": "app_01j...",
"client_name": "Acme Data Exporter",
"grant_types": ["authorization_code", "refresh_token"],
"scope": "read:customers write:reports",
"created_at": "2026-03-30T00:00:00Z",
"status": "active"
}
],
"pagination": { "cursor": "...", "has_more": false }
}
Create Client (Admin)
POST /api/v1/oauth2/clients
Create a client directly without an initial access token. Equivalent to DCR but requires admin credentials.
Headers
Authorization: Bearer <apiKey>X-Bulwark-Tenant: <tenant-id>
Body
Same schema as POST /oauth2/register.
Response 201
Same schema as the DCR 201 response.
Revoke Client
DELETE /api/v1/oauth2/clients/{id}
Immediately revokes the client and all tokens issued to it. Active sessions authenticated via this client will be terminated.
Headers
Authorization: Bearer <apiKey>X-Bulwark-Tenant: <tenant-id>
Response 200
{
"data": {
"client_id": "app_01j...",
"status": "revoked",
"revoked_at": "2026-03-30T14:00:00Z"
}
}