Skip to main content
Version: 1.0

Admin API reference

All Admin API endpoints are under /admin/api/ and require:

X-Admin-API-Key: <key>

The key is configured via the PBAC_ADMIN_API_KEY environment variable (default in dev: dev-admin-key).

All request and response bodies are application/json. List endpoints accept an optional tenantId query parameter to filter by tenant.

Standard HTTP status codes apply: 200 OK, 201 Created, 204 No Content, 404 Not Found, 409 Conflict.


Identity providers

Identity providers (IdPs) are the upstream OIDC providers the AS federates to during the authorization code flow.

GET /admin/api/identity-providers

Lists all IdPs.

Query paramDescription
tenantIdFilter by tenant (optional)

Response — array of IdP objects (see fields below).

GET /admin/api/identity-providers/{idpId}

Returns a single IdP by its idpId (provider key string).

POST /admin/api/identity-providers

Creates an IdP.

Request body:

FieldRequiredTypeDescription
issuerYesstringOIDC issuer URL
idpIdNostringProvider key (auto-generated if omitted)
nameNostringDisplay name
enabledNobooleanDefault true
clientIdNostringClient ID at the upstream IdP
clientSecretNostringClient secret at the upstream IdP
scopesNostring[]Default scopes to request
authorizationEndpointNostringOverride authorization endpoint
tokenEndpointNostringOverride token endpoint
userinfoEndpointNostringOverride userinfo endpoint
jwksUriNostringOverride JWKS URI
tenantIdNostringTenant scoping

Response201 Created, IdP object.

PUT /admin/api/identity-providers/{idpId}

Replaces an IdP. Same body as POST.

DELETE /admin/api/identity-providers/{idpId}

Deletes an IdP. 204 No Content on success.

curl -s -X POST https://pbac.example.com/admin/api/identity-providers \
-H "X-Admin-API-Key: dev-admin-key" \
-H "Content-Type: application/json" \
-d '{
"issuer": "https://idp.example.com",
"name": "Corporate IdP",
"clientId": "pbac-as",
"clientSecret": "secret",
"scopes": ["openid", "profile", "email"]
}'

Resource servers

Resource servers are the APIs that consume tokens issued by this AS and call /introspect to validate them.

GET /admin/api/resource-servers

Lists all resource servers.

Query paramDescription
tenantIdFilter by tenant (optional)

GET /admin/api/resource-servers/{id}

Returns a single resource server by internal numeric ID.

POST /admin/api/resource-servers

Creates a resource server.

Request body:

FieldRequiredTypeDescription
resourceIndicatorYesstringURI identifying the RS (e.g. https://api.example.com/fhir)
nameNostringDisplay name
descriptionNostringFree-text description
capabilityNoobjectArbitrary capability metadata (passed to OPA)
clientIdNointegerInternal PK of the client record used for introspection
enabledNobooleanDefault true
typeUrisNostring[]Resource type URIs served by this RS
tenantIdNostringTenant scoping

Response201 Created, resource server object.

PUT /admin/api/resource-servers/{id}

Replaces a resource server. Same body as POST.

DELETE /admin/api/resource-servers/{id}

Deletes a resource server. 204 No Content on success.

curl -s -X POST https://pbac.example.com/admin/api/resource-servers \
-H "X-Admin-API-Key: dev-admin-key" \
-H "Content-Type: application/json" \
-d '{
"resourceIndicator": "https://api.example.com/fhir",
"name": "FHIR API",
"typeUris": ["https://example.com/Patient"]
}'

Resource types

Resource types categorize protected resources and define the applicable scopes.

GET /admin/api/resource-types

Lists all resource types.

Query paramDescription
tenantIdFilter by tenant (optional)

GET /admin/api/resource-types/{id}

Returns a single resource type by internal numeric ID.

POST /admin/api/resource-types

Creates a resource type.

Request body:

FieldRequiredTypeDescription
typeUriYesstringType URI (e.g. https://example.com/Patient)
nameNostringDisplay name
descriptionNostringFree-text description
parentTypeIdNointegerInternal PK of parent type (for hierarchies)
enabledNobooleanDefault true
scopesNostring[]Scope names applicable to this type
tenantIdNostringTenant scoping

Response201 Created, resource type object.

PUT /admin/api/resource-types/{id}

Replaces a resource type. Same body as POST.

DELETE /admin/api/resource-types/{id}

Deletes a resource type. 204 No Content on success.

curl -s -X POST https://pbac.example.com/admin/api/resource-types \
-H "X-Admin-API-Key: dev-admin-key" \
-H "Content-Type: application/json" \
-d '{
"typeUri": "https://example.com/Patient",
"name": "FHIR Patient",
"scopes": ["read", "write", "delete"]
}'

Resources

Resources are individual protected objects (e.g., a specific FHIR Patient record). Each resource belongs to a resource server and a resource type, and optionally has an owner subject.

GET /admin/api/resources

Lists all resources.

Query paramDescription
tenantIdFilter by tenant (optional)

GET /admin/api/resources/{id}

Returns a single resource by internal numeric ID.

POST /admin/api/resources

Creates a resource.

Request body:

FieldRequiredTypeDescription
resourceServerIdYesintegerInternal PK of the owning resource server
resourceTypeIdYesintegerInternal PK of the resource type
resourceIdentifierYesstringURI or path that identifies this resource
ownerSubjectIdNointegerInternal PK of the owner subject
scopesNostring[]Scope names assigned to this resource
tenantIdNostringTenant scoping

Response201 Created, resource object.

PUT /admin/api/resources/{id}

Replaces a resource. Same body as POST.

DELETE /admin/api/resources/{id}

Deletes a resource. 204 No Content on success.

curl -s -X POST https://pbac.example.com/admin/api/resources \
-H "X-Admin-API-Key: dev-admin-key" \
-H "Content-Type: application/json" \
-d '{
"resourceServerId": 1,
"resourceTypeId": 2,
"resourceIdentifier": "https://api.example.com/fhir/Patient/42",
"scopes": ["read"]
}'

Clients

Clients are OAuth 2.0 clients registered in the system. They can also be created via the dynamic registration endpoint (POST /register).

GET /admin/api/clients

Lists all clients.

Query paramDescription
tenantIdFilter by tenant (optional)

GET /admin/api/clients/{clientId}

Returns a single client by its clientId string.

Query paramDescription
tenantIdFilter by tenant (optional)

POST /admin/api/clients

Creates a client.

Request body:

FieldRequiredTypeDescription
clientIdYesstringUnique client identifier
clientTypeYesstringconfidential or public
clientSecretNostringBCrypt-hashed secret (confidential clients)
enabledNobooleanDefault true
redirectUrisNostring[]Allowed redirect URIs
postLogoutRedirectUrisNostring[]Post-logout redirect URIs
clientNameNostringDisplay name
clientUriNostringHome page URI
logoUriNostringLogo URI
tokenEndpointAuthMethodNostringe.g. client_secret_basic, private_key_jwt
jwksUriNostringHTTPS URI of the client's JWK Set
jwksNoobjectInline JWK Set
softwareStatementNoobjectSoftware statement claims (JSON object)
tenantIdNostringTenant scoping

Note: clientSecret must be BCrypt-hashed before submission. The AS does not hash secrets submitted via the admin API (unlike DCR, which hashes automatically).

Response201 Created, client object.

PUT /admin/api/clients/{clientId}

Replaces a client. Same body as POST.

DELETE /admin/api/clients/{clientId}

Deletes a client. 204 No Content on success.

# Create a confidential client with a pre-hashed secret
curl -s -X POST https://pbac.example.com/admin/api/clients \
-H "X-Admin-API-Key: dev-admin-key" \
-H "Content-Type: application/json" \
-d '{
"clientId": "my-rs",
"clientType": "confidential",
"clientSecret": "$2a$10$...",
"softwareStatement": {
"granted_resources": [
{ "type": "urn:as:introspect", "scopes": ["uma_protection"] }
],
"resources": []
}
}'

Subjects

Subjects represent end-users (identified by their OIDC sub and IdP pair) in the policy model.

GET /admin/api/subjects

Lists all subjects.

Query paramDescription
tenantIdFilter by tenant (optional)

GET /admin/api/subjects/{id}

Returns a single subject by internal numeric ID.

POST /admin/api/subjects

Creates a subject.

Request body:

FieldRequiredTypeDescription
subjectIdYesstringOIDC sub claim value
identityProviderIdNointegerInternal PK of the associated IdP
tenantIdNostringTenant scoping

Response201 Created, subject object.

PUT /admin/api/subjects/{id}

Replaces a subject. Same body as POST.

DELETE /admin/api/subjects/{id}

Deletes a subject. 204 No Content on success.

curl -s -X POST https://pbac.example.com/admin/api/subjects \
-H "X-Admin-API-Key: dev-admin-key" \
-H "Content-Type: application/json" \
-d '{ "subjectId": "alice@example.com", "identityProviderId": 1 }'

Policy rules

Policy rules are Rego (or Cedar) policies stored in the database and served to OPA via the bundle endpoint. Changes take effect after OPA polls the next bundle.

GET /admin/api/policy-rules

Lists all policy rules.

Query paramDescription
tenantIdFilter by tenant (optional)

GET /admin/api/policy-rules/{id}

Returns a single policy rule by internal numeric ID.

POST /admin/api/policy-rules

Creates a policy rule.

Request body:

FieldRequiredTypeDescription
versionYesstringVersion label (e.g. v1)
kindYesstringrego or cedar
pathYesstringRego package path (e.g. oauth/token) — becomes the file path in the bundle
contentYesstringPolicy source code
enabledNobooleanDefault true
digestNostringContent digest for integrity checking
tenantIdNostringTenant scoping

Response201 Created, policy rule object.

PUT /admin/api/policy-rules/{id}

Replaces a policy rule by ID.

PUT /admin/api/policy-rules/by-path?path={path}

Upserts a policy rule by its path. Creates if absent, updates if present.

DELETE /admin/api/policy-rules/{id}

Deletes a policy rule. 204 No Content on success.

curl -s -X POST https://pbac.example.com/admin/api/policy-rules \
-H "X-Admin-API-Key: dev-admin-key" \
-H "Content-Type: application/json" \
-d '{
"version": "v1",
"kind": "rego",
"path": "oauth/token",
"content": "package oauth.token\n\ndefault allow = false\n\nallow {\n input.client.type == \"confidential\"\n}"
}'

Policy data

Policy data is JSON stored in the database and served to OPA as data.<key> keys in the bundle. Rows with no tenantId and no version are included in the shared OPA bundle.

GET /admin/api/policy-data

Lists all policy data entries.

Query paramTypeDescription
tenantIdstringFilter by tenant (optional)
bundledOnlybooleanIf true, return only entries included in the OPA bundle (default false)

GET /admin/api/policy-data/{id}

Returns a single policy data entry by internal numeric ID.

POST /admin/api/policy-data

Creates a policy data entry.

Request body:

FieldRequiredTypeDescription
dataKeyYesstringOPA data key (e.g. oauth) — accessible as data.oauth in Rego
payloadYesstringJSON string to store as the value
versionNostringVersion label
tenantIdNostringTenant scoping; entries with tenantId=null and version=null are bundled

Response201 Created, policy data object. The inBundle field indicates whether this entry is included in the OPA bundle.

PUT /admin/api/policy-data/{id}

Replaces a policy data entry by ID.

PUT /admin/api/policy-data/by-key?dataKey={dataKey}

Upserts a policy data entry by its dataKey. Creates if absent, updates if present.

DELETE /admin/api/policy-data/{id}

Deletes a policy data entry. 204 No Content on success.

curl -s -X POST https://pbac.example.com/admin/api/policy-data \
-H "X-Admin-API-Key: dev-admin-key" \
-H "Content-Type: application/json" \
-d '{
"dataKey": "oauth",
"payload": "{\"resource\":{\"types\":{\"https://example.com/Patient\":{\"scopes\":[\"read\",\"write\"]}}}}"
}'

Audit logs

Audit logs are append-only records of AS operations. Read-only via the API.

GET /admin/api/audit-logs

Returns a paginated list of audit log entries.

Query paramDescription
endpointFilter by endpoint path (e.g. /token)
tenantIdFilter by tenant
clientIdFilter by client ID
pagePage number (0-indexed, default 0)
sizePage size (default 20)
sortSort field and direction (e.g. createdAt,desc)

Response200 OK, Spring Page wrapper:

{
"content": [ ... ],
"totalElements": 42,
"totalPages": 3,
"number": 0,
"size": 20
}

Each entry:

FieldDescription
idInternal numeric ID
endpointRequest path
methodHTTP method
requestSummaryKey request fields (token presence, auth type, etc.)
policyInputOPA input that was evaluated
policyDecisionOPA output
outcomeallow, deny, or error
tenantIdTenant context
clientIdClient that made the request
subjectIdSubject (if applicable)
ipClient IP address
userAgentUser-Agent header
createdAtISO 8601 timestamp

GET /admin/api/audit-logs/{id}

Returns a single audit log entry by internal numeric ID.

curl -s "https://pbac.example.com/admin/api/audit-logs?endpoint=/token&size=5&sort=createdAt,desc" \
-H "X-Admin-API-Key: dev-admin-key"

Next steps

  • OAuth Endpoints Reference — Token, authorize, introspect, register, and AuthZEN endpoints
  • Base Provisioning — Step-by-step guide to setting up IdPs, resource servers, and types
  • Policy Data — Configure denylists, entitlements, and trust issuers via the policy data API