Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Admin API

Mounted under /api/admin/. All endpoints require a valid session cookie with an appropriate RBAC permission. Configure permissions via [[rbac.role]] in the configuration file — without a role that grants * or the specific permission, every admin request returns 403 Forbidden.

See Configuration Reference — [rbac] for the full permission list and role setup.


Client Registry

MethodPathPermissionDescription
GET/api/admin/clientsclients:readList all registered OAuth2 clients.
POST/api/admin/clientsclients:writeCreate a new client registration.
GET/api/admin/clients/{client_id}clients:readGet a single client registration.
PUT/api/admin/clients/{client_id}clients:writeUpdate a client registration. Fields omitted from the PUT body are preserved from the existing record. In particular, token_endpoint_auth_method is not reset to a default when the field is absent from the request — this prevents public PKCE clients (registered with token_endpoint_auth_method: "none") from being silently converted to private_key_jwt on the next edit.
DELETE/api/admin/clients/{client_id}clients:writeDelete a client registration.

Redirect URI scheme enforcement (RFC 9700 §2.6): All redirect_uris in POST and PUT requests must use https://, or http:// with a loopback host only (localhost, 127.0.0.1, or ::1). Any other http:// URI is rejected with 400 Bad Request.

Client fields reference

FieldTypeDescription
client_namestringHuman-readable name shown in the admin WebUI and on consent screens.
redirect_urislist of stringsAllowed redirect URIs for the authorization code flow. Must be https:// or loopback http://.
scopeslist of stringsScopes the client is permitted to request.
token_endpoint_auth_methodstringHow the client authenticates at the token endpoint. One of: private_key_jwt, client_secret_jwt, client_secret_basic, client_secret_post, tls_client_auth, self_signed_tls_client_auth, none, or kerberos_client_auth.
client_secretstringShared secret. Required for client_secret_* methods; must not be set for kerberos_client_auth.
jwks_uristringURL of the client’s JWKS endpoint. Required for private_key_jwt; must not be set for kerberos_client_auth.
tls_client_certificatestringPEM-encoded client certificate for mTLS authentication. Required for tls_client_auth / self_signed_tls_client_auth; must not be set for kerberos_client_auth. The server stores only the SHA-256 thumbprint.
kerberos_principalstringExact Kerberos service principal for single-machine kerberos_client_auth clients (e.g. "host/node1.example.com@EXAMPLE.COM"). Must contain / and @. Mutually exclusive with kerberos_principal_pattern. Only accepted when [ipa] gssapi = true.
kerberos_principal_patternstringGlob pattern for template kerberos_client_auth clients (e.g. "host/*@EXAMPLE.COM"). * matches any characters except @. Must contain @. At most three wildcards allowed. Mutually exclusive with kerberos_principal. Only accepted when [ipa] gssapi = true.
kerberos_hbac_servicestringOptional. FreeIPA HBAC service name that gates access via the replicated HBAC rule set. Only meaningful for kerberos_client_auth clients. When set and the HBAC rule set is empty, all token requests are denied (fail-closed).
spiffe_idstringOptional. SPIFFE ID URI (e.g. "spiffe://example.org/workload/myapp") bound to this client. When set, ahdapa recognises workloads presenting an X.509-SVID whose URI SAN matches this value for mTLS authentication. See SPIFFE Integration.
workload_typestring or nullOptional. Machine-readable workload category label (e.g. "pipeline-agent"). When the client performs an RFC 8693 OBO token exchange as the actor, this value is embedded in the act.workload_type claim of the issued token. It is resolved from the CRDT registration at token issuance time — not from the actor token — to prevent label spoofing. Defaults to null.
allow_token_exchange_actorbooleanGate that controls whether this client may supply actor_token in a token exchange request. When false (the default), any request that includes actor_token is rejected immediately with 403 access_denied before subject token validation. Set to true for clients that are authorised OBO actors.

kerberos_client_auth constraints enforced by the admin API:

  • [ipa] gssapi = true must be configured on the server; otherwise the request is rejected with 400 Bad Request.
  • Exactly one of kerberos_principal or kerberos_principal_pattern must be set.
  • kerberos_principal must match the format service/host@REALM (contains / and @).
  • kerberos_principal_pattern must contain @ and at most three * wildcards.
  • kerberos_client_auth is mutually exclusive with client_secret, jwks_uri, and tls_client_certificate.
  • kerberos_client_auth is rejected by POST /register (dynamic registration); use the admin API.

Signing Keys

MethodPathPermissionDescription
GET/api/admin/keyskeys:readList active signing keys and their algorithms.
POST/api/admin/keys/rotatekeys:rotateRotate the active signing key (generates a new key; old key is retained for verification).
DELETE/api/admin/keys/{kid}keys:rotateRevoke a signing key by tombstoning its OR-Map entry. The key is immediately removed from the JWKS endpoint and from all cluster nodes via gossip. Returns 404 if the kid is not found. Logs a warning if the revoked key is the currently active kid; follow with a key rotation.
GET/api/admin/keys/clusterkeys:readGet the cluster AEAD wrapping key metadata (UUID identifier and rotation timestamp). The raw key is never exposed.
PUT/api/admin/keys/clusterkeys:rotateSet a new cluster AEAD wrapping key.

Cluster Nodes

MethodPathPermissionDescription
GET/api/admin/nodesnodes:readList all known cluster nodes and their last-seen state.

Sessions and Refresh Tokens

MethodPathPermissionDescription
GET/api/admin/refresh-familiesusers:readList all active refresh-token families.
DELETE/api/admin/refresh-families/{family_id}users:writeRevoke all tokens in a refresh-token family (force re-login).

Federated Accounts

MethodPathPermissionDescription
GET/api/admin/federated-accountsfederation:readList all federated-account linkages.
POST/api/admin/federated-accountsfederation:writeCreate a federated-account linkage.
DELETE/api/admin/federated-accounts/{id}federation:writeRemove a federated-account linkage.

IPA Identity Providers (Auto-discovered)

These endpoints expose the IPA-sourced upstream IdPs that ahdapa discovers automatically from cn=idp,<suffix> LDAP objects. All LDAP-sourced attributes are read-only; only the default_acr and default_amr override fields can be written via the admin API or the IPA Upstream IdPs page in the WebUI.

MethodPathPermissionDescription
GET/api/admin/federation/ipa-idpsfederation:readList all IPA-discovered upstream IdPs with their current ACR/AMR override values. Returns an empty array when [ipa] gssapi is not enabled or no ipaIdP objects exist.
GET/api/admin/federation/ipa-idps/{id}federation:readGet a single IPA IdP by its identifier (e.g. ipa-google-workspace). Returns 404 if the IdP is not present in the current in-memory list (i.e. not in the last LDAP refresh).
PUT/api/admin/federation/ipa-idps/{id}federation:writeSet the ACR/AMR override for an IPA IdP. Persisted in the CRDT and gossiped to all cluster nodes. The LDAP-sourced fields (issuer, client_id, scopes, callback_path) are read-only and must be managed in FreeIPA.

GET /api/admin/federation/ipa-idps response (array of):

{
  "id":           "ipa-google-workspace",
  "display_name": "Google Workspace",
  "issuer":       "https://accounts.google.com",
  "client_id":    "123…apps.googleusercontent.com",
  "scopes":       ["openid", "email", "profile"],
  "callback_path":"/internal/callback/ipa-google-workspace",
  "default_acr":  null,
  "default_amr":  [],
  "source":       "ipa"
}

PUT /api/admin/federation/ipa-idps/{id} request body:

{
  "default_acr": "urn:oasis:names:tc:SAML:2.0:ac:classes:InternetProtocolPassword",
  "default_amr": ["pwd", "fed"]
}

Send "default_acr": null and "default_amr": [] to clear overrides (fall back to LDAP-sourced values or the built-in unspecified ACR).


Users and Groups (read-only)

MethodPathPermissionDescription
GET/api/admin/usersusers:readList users visible to the server (static users file).
GET/api/admin/users/{username}users:readGet a single user record.
GET/api/admin/groupsusers:readList groups.
GET/api/admin/groups/{name}users:readGet a single group and its members.

Scope Management

Scope definitions control which OIDC claims are returned for each OAuth2 scope name. Eight built-in scopes (openid, offline_access, profile, email, phone, address, groups, directory.read) are seeded on first startup and cannot be deleted. Custom scopes can be created and edited freely.

The directory.read scope gates access to the machine-readable identity API (/api/identity/). It carries no OIDC claims of its own — it is an authorization scope, not a claims scope. See Identity API for endpoint details.

MethodPathPermissionDescription
GET/api/admin/scopesscopes:readList all scope definitions. Returns an array of {name, description, claims, is_system} objects.
PUT/api/admin/scopes/{name}scopes:writeCreate or update a scope definition. Body: {"description":"…","claims":["claim1","claim2"]}. Returns 403 for built-in system scopes. Changes are replicated to all cluster nodes via gossip.
DELETE/api/admin/scopes/{name}scopes:writeDelete a custom scope via tombstone. Returns 403 for built-in system scopes.

Identity HBAC Policies

MethodPathPermissionDescription
GET/api/admin/hbachbac:readList all HBAC policy rules.
POST/api/admin/hbachbac:writeCreate a new HBAC rule.
GET/api/admin/hbac/{rule_id}hbac:readGet a single HBAC rule.
PUT/api/admin/hbac/{rule_id}hbac:writeUpdate a rule (partial update; omitted fields are preserved).
DELETE/api/admin/hbac/{rule_id}hbac:writeDelete a rule.

See Identity HBAC for policy semantics.

The following fields are present on HBAC rules and control RFC 8693 OBO delegation target enforcement. They appear in GET responses and can be modified via the PATCH (PUT) endpoint.

FieldTypeDefaultDescription
delegation_targetsstring[][]List of Kerberos SPNs (e.g. "host/backend.example.com") this rule permits as the target_service in a token exchange request. An empty list means no SPN is explicitly allowed unless delegation_target_category is true.
delegation_target_categorybooleanfalseWildcard flag. When true, any target_service value is accepted by this rule, regardless of the delegation_targets list.
delegation_target_countinteger(read-only)Count of SPNs currently in delegation_targets. Included in GET responses; ignored on writes.

To modify delegation targets via the PATCH endpoint, use:

Patch fieldTypeEffect
add_delegation_targetsstring[]Add one or more SPNs to delegation_targets.
remove_delegation_targetsstring[]Remove one or more SPNs from delegation_targets.
delegation_target_categorybooleanSet the wildcard flag directly.
# Permit a specific backend SPN
curl -s -b session.jar \
  -X PUT -H 'Content-Type: application/json' \
  -d '{"add_delegation_targets": ["host/backend.example.com"]}' \
  https://idp.example.com/api/admin/hbac/<rule-id>

# Remove a previously permitted SPN
curl -s -b session.jar \
  -X PUT -H 'Content-Type: application/json' \
  -d '{"remove_delegation_targets": ["host/old-backend.example.com"]}' \
  https://idp.example.com/api/admin/hbac/<rule-id>

# Enable wildcard (any target_service allowed by this rule)
curl -s -b session.jar \
  -X PUT -H 'Content-Type: application/json' \
  -d '{"delegation_target_category": true}' \
  https://idp.example.com/api/admin/hbac/<rule-id>

SPIFFE Workload Entries

These endpoints are active only when [spiffe] trust_domain is set. They manage the workload registration entries that the Workload API uses to attest callers and issue SVIDs. See SPIFFE Integration for the full setup guide.

MethodPathPermissionDescription
GET/api/admin/spiffe/entriesspiffe:readList all workload registration entries, sorted by SPIFFE ID.
POST/api/admin/spiffe/entriesspiffe:writeCreate a new workload registration entry. Returns 201 Created with the new entry including its server-assigned id.
GET/api/admin/spiffe/entries/{id}spiffe:readGet a single workload registration entry by its UUID. Returns 404 if not found.
PUT/api/admin/spiffe/entries/{id}spiffe:writeReplace a workload registration entry. Returns 404 if the entry does not exist.
DELETE/api/admin/spiffe/entries/{id}spiffe:writeDelete a workload registration entry. Returns 404 if not found, 204 No Content on success.
GET/api/admin/spiffe/statusspiffe:readReturn SPIFFE CA status for the current node.

Selector lookup endpoints

These endpoints are used by the admin WebUI SelectorBuilder to resolve human-readable names to numeric IDs. They accept a ?q=PREFIX query parameter and return at most 20 results, searching static users first and then IPA/LDAP.

MethodPathPermissionDescription
GET/api/admin/spiffe/lookup/users?q=PREFIXspiffe:readSearch users by username prefix. Returns an array of {value, label, uid_number} objects where value is the username, label is the display name, and uid_number is the POSIX UID (or null if not available). Used to look up UID numbers by name for Uid selectors.
GET/api/admin/spiffe/lookup/groups?q=PREFIXspiffe:readSearch groups by name prefix. Returns an array of {value, label, gid_number} objects where value is the group name, label is the display name, and gid_number is the POSIX GID (or null if not available). Used to look up GID numbers by name for Gid and SupplementalGid selectors.
GET/api/admin/spiffe/lookup/hostgroups?q=PREFIXspiffe:readSearch IPA host groups by name prefix. Returns an array of {value, label} objects where value and label are both the host group name. Used to populate Hostgroup selectors.

Example responses:

GET /api/admin/spiffe/lookup/users?q=alice:

[{"value": "alice", "label": "Alice Admin", "uid_number": 10001}]

GET /api/admin/spiffe/lookup/groups?q=web:

[{"value": "web-servers", "label": "web-servers", "gid_number": 8001}]

GET /api/admin/spiffe/lookup/hostgroups?q=web:

[{"value": "web-servers", "label": "web-servers"}]

Workload entry fields

FieldTypeRequiredDescription
spiffe_idstringyesSPIFFE ID URI to issue to matching workloads, e.g. "spiffe://example.org/workload/myapp". Must be a valid SPIFFE ID.
selectorslist of stringsnoWorkload attestation selectors stored as JSON-encoded objects. Each element is a JSON string with a "type" tag and a "value" field. Eight types are supported — see table below. A workload must match all selectors in an entry to receive that SPIFFE ID. Defaults to [].
node_constraintstring or nullnoRestrict this entry to a specific cluster node ID. null means any node.
ttl_secondsintegernoSVID TTL override in seconds. 0 uses the global [spiffe] svid_ttl_seconds default.

The id field (UUID string) is assigned by the server on POST and returned in the response body. Supply it in the path for GET, PUT, and DELETE requests.

Selector type reference

"type""value" typeMatch conditionAttestation path
Uidinteger (u32)Caller’s Unix UID equals the valueLocal Unix socket only (SO_PEERCRED)
Gidinteger (u32)Caller’s primary GID equals the valueLocal Unix socket only (SO_PEERCRED)
SupplementalGidinteger (u32)Caller’s supplemental group list (from /proc/<pid>/status Groups:) contains the valueLocal Unix socket only
Pathstring/proc/<pid>/exe symlink resolves to this absolute pathLocal Unix socket only
HostnamestringMachine hostname equals the valueLocal (from /proc/sys/kernel/hostname) or remote (caller-declared)
HostgroupstringMachine belongs to this IPA host group (server-verified via LDAP)Local and remote
ImaHashstring ("alg:hexdigest")Hash of the running executable matches; supported algorithms: sha256, sha512, sha1Local (computed at accept time) or remote (caller-declared via ima_hash field)
NodeIdstringAttestation occurs on the named Ahdapa nodeLocal and remote

Selector JSON examples:

{"type": "Uid",           "value": 1000}
{"type": "Gid",           "value": 1000}
{"type": "SupplementalGid","value": 5000}
{"type": "Path",          "value": "/usr/bin/myapp"}
{"type": "Hostname",      "value": "web01.example.org"}
{"type": "Hostgroup",     "value": "web-servers"}
{"type": "ImaHash",       "value": "sha256:deadbeef..."}
{"type": "NodeId",        "value": "node1.example.org"}

When passed in the selectors array of a create/update request, each object must be JSON-encoded as a string:

{
  "spiffe_id": "spiffe://example.org/workload/myapp",
  "selectors": [
    "{\"type\":\"Uid\",\"value\":1000}",
    "{\"type\":\"Path\",\"value\":\"/usr/bin/myapp\"}"
  ]
}

The admin WebUI SelectorBuilder handles this encoding automatically.

SPIFFE status response

GET /api/admin/spiffe/status returns:

FieldTypeDescription
trust_domainstring or nullConfigured trust domain, or null when SPIFFE is not enabled.
ca_algorithmstringKey algorithm of the active CA (e.g. "EC-P256").
bundle_sequenceintegerMonotonically increasing bundle sequence counter (0 when no bundle is loaded yet).
refresh_hintintegerConfigured bundle_refresh_hint in seconds.
entry_countintegerNumber of live workload registration entries.
workload_socketstringFilesystem path of the Workload API Unix socket.
hsm_backedbooleantrue when the CA private key is held in an HSM (PKCS#11) and not in the CRDT.

Audit Log

MethodPathPermissionDescription
GET/api/admin/auditaudit:readList audit events, most recent first. Returns at most 100 events per call. Supports ?offset=<n> for pagination.

Audit event schema

Each event object contains:

FieldTypeDescription
idintegerAuto-incrementing event ID.
event_typestringEvent type identifier (see table below).
substringSubject — the user or machine principal involved. Omitted when not applicable (e.g. client-credentials flows that do not have a user subject).
client_idstringOAuth2 client ID involved. Omitted when not applicable (e.g. login events).
detailstringFree-form detail string. Format varies by event type.
created_atintegerUnix timestamp (seconds).

Event types

event_typesubclient_iddetail
kerberos_client_authAuthenticated principal (actual machine principal for template clients, e.g. host/node1.example.com@REALM).Template client_id.Space-separated granted scope string, e.g. openid directory.read.
login_successAuthenticated user UPN.
jwt_bearerSubject from bearer assertion.Client ID.iss=<issuer> jti=<jti> of the upstream assertion.
ipa_idp_acr_updatedAdmin who made the change.{"idp_id":"<id>"}

Template client sub: When a kerberos_client_auth client uses kerberos_principal_pattern (template mode), the sub in the audit event is the actual authenticated machine principal (e.g. host/node1.example.com@EXAMPLE.COM), not the template client_id. This makes individual machines distinguishable in audit records even though they share a single client registration.

Admin WebUI behaviour: In the audit log page, subjects that contain / (service principals such as host/node1.example.com@REALM) are rendered as plain text. Subjects without / (regular users) are rendered as clickable links to the user detail page.