Protocol Endpoints
All endpoints are served from the root of the configured server.issuer URL.
Unauthenticated requests to protected endpoints return 401 Unauthorized.
These are the endpoints consumed by OAuth2/OIDC clients, browsers, and end users. For admin-only endpoints see Admin API; for inter-node endpoints see Internal / Gossip API.
OIDC / OAuth2 Discovery
These endpoints are mounted under /.well-known/.
| Method | Path | Description |
|---|---|---|
GET | /.well-known/openid-configuration | OIDC Provider Metadata (RFC 8414 / OIDC Core §4) |
GET | /.well-known/oauth-authorization-server | OAuth2 Authorization Server Metadata (RFC 8414) |
GET | /.well-known/openid-federation | OIDC Federation 1.0 Entity Statement |
Core OAuth2 / OIDC
| Method | Path | RFC / Spec | Description |
|---|---|---|---|
GET POST | /authorize | RFC 6749 §4.1, RFC 7636, RFC 9700 §4.2.4 | Authorization endpoint. Initiates the Authorization Code flow (with optional PKCE). Handles Authorization: Negotiate before query-string parsing: on success authenticates the user, creates a session, and continues the OAuth2 flow in the same request; on Continue returns 401; when absent falls back to the session-cookie flow or redirects to the login page. Requested scopes are silently intersected with the client’s current allowed scope set before being stored in the consent token (RFC 6749 §3.3): if the client’s scope set was narrowed after the user obtained a session, the consent page reflects only the permitted intersection. Returns invalid_scope if the intersection is empty. Responses from this endpoint carry Referrer-Policy: no-referrer (RFC 9700 §4.2.4) to prevent OAuth parameters in the URL from leaking to third-party resources. |
POST | /token | RFC 6749 §5.1, §4.1.3 | Token endpoint. Exchanges an authorization code, refresh token, or device code for access/refresh/ID tokens. For the authorization_code grant, redirect_uri is mandatory (RFC 6749 §4.1.3): a missing redirect_uri returns invalid_request; a mismatched value returns invalid_grant. |
POST | /revoke | RFC 7009 | Token revocation. Accepts an access token or refresh token. Revoking a refresh token invalidates its entire family. |
POST | /introspect | RFC 7662 | Token introspection. Returns active/inactive status and claims for a presented token. |
GET POST | /userinfo | OIDC Core §5.3 | UserInfo endpoint. Returns claims for the authenticated user from the Bearer token. |
GET | /jwks | RFC 7517 | JSON Web Key Set — public keys used to verify tokens. Rotated via the admin API. |
POST | /par | RFC 9126 | Pushed Authorization Request. Accepts authorization parameters and returns a request_uri for use in /authorize. |
POST | /device_authorization | RFC 8628 | Device Authorization endpoint. Issues a device_code and user_code for device-flow clients. |
GET POST | /device | RFC 8628 | Device verification page. Users enter their user_code here to authorize a device. |
POST | /register | RFC 7591 | Dynamic Client Registration. Accepts two authorization paths: (1) Authorization: Bearer <registration_token> when server.registration_token is configured, or (2) a session cookie whose sub is a service principal from the server’s own Kerberos realm (e.g. HTTP/client.ipa.test@IPA.TEST). User principals are excluded from path (2). Returns 404 only when neither path is available (no registration_token and no valid service-principal session). |
Dynamic Client Registration (POST /register)
The POST /register endpoint (RFC 7591) supports two independent authorization
paths. A request that satisfies either path is accepted; one that satisfies
neither receives 404 Not Found.
Path 1 — Pre-shared initial access token
POST /register
Authorization: Bearer <registration_token>
Content-Type: application/json
Requires server.registration_token to be set in the configuration. When that
key is absent this path is unavailable. The token is compared in constant time.
Path 2 — Kerberos service-principal session
A session cookie whose sub claim is a service principal from the server’s own
Kerberos realm authorizes registration without any pre-shared secret. The sub
must match <service>/<host>@<realm> — that is, the local part (before @)
must contain a / character. User principals (alice@REALM) are explicitly
excluded. Cross-realm principals (realm does not match server.realm) are also
excluded.
The session is obtained via SPNEGO at POST /authorize with no OAuth2
parameters, which returns 400 + Set-Cookie (rather than a redirect, which
would cause curl to drop the cookie):
# 1. Load the service principal's TGT
kinit -k -t /etc/http.keytab HTTP/client.ipa.test@IPA.TEST
# 2. Authenticate via SPNEGO; the 400 is expected — the session cookie is set.
curl -s -o /dev/null -w "%{http_code}\n" \
--negotiate -u: \
-c /tmp/session.jar \
https://m1.ipa.test/idp/authorize
# → 400
# 3. Register the OAuth2 client using the saved session cookie.
curl -s \
-b /tmp/session.jar \
-X POST \
-H 'Content-Type: application/json' \
-d '{
"redirect_uris": ["https://client.ipa.test/callback"],
"client_name": "client.ipa.test",
"scope": "openid profile email",
"token_endpoint_auth_method": "client_secret_basic"
}' \
https://m1.ipa.test/idp/register | python3 -m json.tool
The 400 from step 2 is intentional: /authorize received no client_id or
other OAuth2 parameters, so there is no flow to start. The error body is
{"error":"invalid_request","error_description":"client_id required"}. Despite
the error status, the Set-Cookie header is present and curl saves the cookie.
The status does not indicate a SPNEGO failure.
Redirect URI scheme enforcement
All redirect_uris supplied in the registration body must use https:// or, for native
applications on loopback only, http:// with a loopback host (localhost, 127.0.0.1,
or ::1). Any other http:// URI causes the registration to fail with
invalid_redirect_uri (RFC 9700 §2.6). This constraint is enforced for both
authorization paths above.
kerberos_client_auth is not available via dynamic registration
Specifying "token_endpoint_auth_method": "kerberos_client_auth" in the registration
body returns 400 Bad Request with "error": "invalid_client_metadata" regardless of
which authorization path is used. Kerberos clients must be registered through the admin
API (POST /api/admin/clients). See Kerberos client authentication.
Response
A successful registration returns 201 Created with a JSON body:
{
"client_id": "550e8400-e29b-41d4-a716-446655440000",
"client_name": "client.ipa.test",
"redirect_uris": ["https://client.ipa.test/callback"],
"token_endpoint_auth_method": "client_secret_basic",
"scope": "openid profile email",
"client_secret": "A3tR…base64url-encoded-32-random-bytes…",
"registration_client_uri": "https://m1.ipa.test/api/admin/clients/550e8400-e29b-41d4-a716-446655440000"
}
client_secret is server-generated when not supplied in the request body; save
it — it is not stored in recoverable form and cannot be retrieved later.
registration_client_uri points to the admin API entry for the newly created
client. The client is immediately visible at GET /api/admin/clients/{client_id}
and is replicated to other cluster nodes via gossip.
Login UI
Browser-facing endpoints used during interactive login flows.
| Method | Path | Description |
|---|---|---|
GET | /login | Redirect to the SPA login page at /ui/auth/login. |
GET | /ui/auth/login | Serve the SPA login page. Inspects Authorization: Negotiate before serving HTML: on a valid Kerberos token sets a session cookie and redirects to ?return_to; on Continue returns 401; when absent or invalid serves the SPA HTML for password/passkey login. |
POST | /login | Submit username and password credentials. On success, issues a session cookie. On PAM PasswordExpired, redirects to /login/change-password. |
GET | /login/change-password | Render the change-password page. Receives ?username= and ?next= query parameters. Only reachable via redirect from POST /login. Requires the pam feature. |
POST | /login/change-password | Submit old and new passwords. On success, issues a session cookie and redirects to next. Requires the pam feature. |
Passkey (WebAuthn)
Requires an active session cookie unless noted. Passkey endpoints are only
functional when passkey_rp_id is set in [ipa].
| Method | Path | Description |
|---|---|---|
POST | /api/auth/passkey/begin | Begin passkey authentication. Returns a WebAuthn PublicKeyCredentialRequestOptions challenge. |
POST | /api/auth/passkey/complete | Complete passkey authentication. Verifies the authenticator assertion and issues a session cookie. |
POST | /api/auth/passkey/register/begin | Begin passkey registration for the current user. Requires a session. |
POST | /api/auth/passkey/register/complete | Complete passkey registration. Stores the new credential in FreeIPA. |
GET | /api/auth/passkeys | List passkeys registered for the current user. Requires a session. |
DELETE | /api/auth/passkeys/{id} | Delete a passkey by its credential ID. Requires a session. |
Session / WebUI Auth API
Used by the management WebUI. All endpoints require a valid session cookie unless noted.
| Method | Path | Description |
|---|---|---|
POST | /api/auth/login | JSON login endpoint for the WebUI. Accepts {"username":"…","password":"…"}. |
POST | /api/auth/otp | JSON OTP login: {"username":"…","password":"…","otp_code":"…"}. Rate-limited. Issues a session cookie on success. No authentication required. |
POST | /api/auth/logout | Invalidate the current session cookie. |
GET | /api/auth/me | Return the username and groups of the current session. |
GET | /api/auth/profile | Return the full user profile (display name, email, groups) from LDAP. |
GET | /api/auth/info | Return server information (issuer, realm, feature flags, display_name). Also returns logo_url and default_theme when the corresponding [webui] keys are configured, for use by the WebUI branding and theme system. No authentication required. |
GET | /api/auth/providers | List configured upstream identity providers (for the WebUI login chooser). No authentication required. |
GET | /api/auth/federated-hint | Return the preferred upstream IdP for a given username hint (?username=). No authentication required. Checks the local federated_accounts table first (fast path). When no entry is found and [ipa] gssapi = true, falls back to an IPA LDAP lookup using the service principal credential: if ipauserauthtype=idp is set on the user, returns {"upstream_id":"ipa-<slug>"} so the UI can redirect a first-time IPA IdP user before any account linkage record exists. |
GET | /api/auth/consent | Render the OAuth2 consent page for the current pending authorization. |
POST | /api/auth/consent | Submit the consent decision (approve / deny). |
GET | /api/auth/device | Look up a pending device-flow request by user_code. Requires a session. |
POST | /api/auth/device | Approve or deny a pending device-flow request. Requires a session. |
User Self-Service
Mounted under /api/me/. All endpoints require a valid session cookie. Operations are
scoped to the authenticated user — no privilege escalation is possible.
OTP tokens
| Method | Path | Description |
|---|---|---|
GET | /api/me/otp-tokens | List OTP tokens enrolled for the current user. Returns a JSON array of token metadata; the raw secret (ipatokenOTPkey) is never included. |
POST | /api/me/otp-tokens | Create a new TOTP token. Body: {"label":"…"}. Returns {"token_id":"…","otpauth_uri":"…"} (201 Created). The otpauth_uri is shown once and not stored — present it to the user immediately (e.g. as a QR code). |
DELETE | /api/me/otp-tokens/{token_id} | Delete an OTP token by its unique ID. Returns 204 on success, 404 if the token does not exist or is not owned by the current user. |
Federation callbacks
Endpoints used during upstream IdP authentication flows.
| Method | Path | Description |
|---|---|---|
GET | /auth/external/{upstream_id} | Initiate authentication delegation to an upstream IdP configured as [[federation.upstream_idps]]. |
GET | /internal/callback/{upstream_id} | Receive the authorization code callback from an upstream IdP. |
POST | /backchannel/logout/{upstream_id} | Receive a back-channel logout notification from an upstream IdP (RFC 9266 / OIDC Back-Channel Logout 1.0). |
SPIFFE Trust Bundle
This endpoint is active only when [spiffe] trust_domain is set in the configuration.
| Method | Path | Auth | Description |
|---|---|---|---|
GET | /.well-known/spiffe-bundle | None | SPIFFE trust bundle for the configured trust domain. Returns an application/json JWK Set containing the X.509 CA certificate (x509-svid use) and the active JWT signing keys (jwt-svid use). Also served at /spiffe/bundle. |
POST | /spiffe/jwt-svid | Bearer token | Exchange an OAuth2 access token for one or more JWT-SVIDs. Supports simple exchange (client spiffe_id) and hostname-based remote attestation. Also served at /.well-known/spiffe/jwt-svid. |
POST | /spiffe/issue-svid | Bearer token (kerberos_client_auth) | Proxy-facing SVID issuance. Accepts workload identity parameters forwarded by a trusted ahdapa-spiffe-proxy node and returns JWT-SVIDs and/or X.509-SVIDs for matching registration entries. Also served at /.well-known/spiffe/issue-svid. |
Response format
{
"keys": [
{
"use": "x509-svid",
"kid": "ca",
"kty": "EC",
"crv": "P-256",
"x": "…",
"y": "…",
"x5c": ["<base64-DER-cert>"]
},
{
"use": "jwt-svid",
"kid": "…",
"kty": "EC",
"crv": "P-256",
"x": "…",
"y": "…"
}
],
"spiffe_sequence": 1,
"spiffe_refresh_hint": 300
}
spiffe_sequence is a monotonically increasing counter incremented on each CA
reload or key rotation. Consumers can use it to detect bundle updates without
comparing key material. spiffe_refresh_hint (seconds) is the value of
[spiffe] bundle_refresh_hint in the configuration.
When SPIFFE is not configured ([spiffe] trust_domain absent), the endpoint
returns 404 Not Found. When SPIFFE is configured but the CA has not yet
finished initialising, the endpoint returns 503 Service Unavailable.
SPIFFE JWT-SVID Exchange
This endpoint completes the bidirectional OAuth2 ↔ SPIFFE bridge.
It requires [spiffe] trust_domain to be set.
| Method | Path | Auth | Description |
|---|---|---|---|
POST | /spiffe/jwt-svid | Bearer access token | Exchange an OAuth2 access token for one or more JWT-SVIDs. Supports two modes: simple exchange (uses the client’s registered spiffe_id) and remote attestation (hostname-based selector matching against workload registration entries). |
Request
POST /spiffe/jwt-svid
Authorization: Bearer <access-token>
Content-Type: application/json
{
"audience": ["https://target-service.example.org"],
"hostname": "web01.example.org",
"ima_hash": "sha256:deadbeef..."
}
| Field | Type | Required | Description |
|---|---|---|---|
audience | array of strings | no | JWT aud claim values. When absent or empty, defaults to [server.issuer], which is always a valid non-empty audience as required by the SPIFFE JWT-SVID spec. |
hostname | string | no | Caller-declared machine hostname. When present, triggers remote attestation: the server looks up IPA host group memberships for this hostname via LDAP (server-verified) and matches all live workload registration entries using Hostname, Hostgroup, ImaHash, and NodeId selectors. Uid, Gid, SupplementalGid, and Path selectors never match remote callers. |
ima_hash | string | no | Caller-declared executable hash in "alg:hexdigest" format (e.g. "sha256:deadbeef..."). Supported algorithms: sha256, sha512, sha1. Only used when hostname is also provided. Allows ImaHash selectors to match in the remote attestation path. |
Attestation flow when hostname is provided:
- The server performs an LDAP lookup to find which IPA host groups the declared hostname belongs to (this step is server-controlled and cannot be bypassed by the caller).
- A remote
AttestationContextis built with UID=u32::MAX, GID=u32::MAX(sentinel values), the declared hostname, the LDAP-resolved host groups, and the parsedima_hash(if provided). - All live registration entries are evaluated; each matching entry produces one JWT-SVID with that entry’s SPIFFE ID.
- If no entries match, the handler falls back to the client’s registered
spiffe_id(single SVID). - If neither path yields a SPIFFE ID,
403 Forbiddenis returned.
When hostname is absent: a single JWT-SVID is issued using the spiffe_id registered on the OAuth2 client. Returns 403 if the client has no spiffe_id.
Response
{
"svids": [
{
"spiffe_id": "spiffe://example.org/workload/myapp",
"svid": "<compact-jwt>",
"hint": ""
}
],
"bundle": "<trust-bundle-jwks-json>"
}
svids is an array — one element per matched SPIFFE ID. In the simple (no hostname) path it always contains exactly one element. In the remote attestation path it may contain multiple elements when several registration entries match.
bundle is the raw JWK Set JSON from /.well-known/spiffe-bundle, included so callers can verify the SVID without a separate round-trip.
Error codes
| Status | Condition |
|---|---|
400 | Malformed request body |
401 | Missing, invalid, expired, or revoked Bearer token |
403 | Token is valid but neither remote attestation nor client spiffe_id yielded a SPIFFE ID |
404 | SPIFFE is not configured ([spiffe] trust_domain absent) |
503 | JWT signing key not yet initialised on this node |
SPIFFE Proxy SVID Issuance
This endpoint is the machine-to-machine counterpart of POST /spiffe/jwt-svid.
It is designed exclusively for the ahdapa-spiffe-proxy daemon running on
IPA-enrolled non-Ahdapa hosts. End-user workloads must not call this endpoint
directly. It requires [spiffe] trust_domain to be set.
| Method | Path | Auth | Description |
|---|---|---|---|
POST | /spiffe/issue-svid | Bearer token (kerberos_client_auth only) | Issue JWT-SVIDs and/or X.509-SVIDs for a workload attested by a trusted proxy. Also served at /.well-known/spiffe/issue-svid. |
Authorization
Two checks are applied after token validation:
- The OAuth2 client whose token is presented must have
token_endpoint_auth_method = "kerberos_client_auth". Any other authentication method returns403 Forbidden. - The Kerberos principal stored on the client must have a service component (the part before the first
/) that appears in[spiffe] accepted_proxieson the server. When the default["host", "HTTP"]is in effect, standard IPA host principals (host/myhost@REALM) and HTTP service principals (HTTP/myhost@REALM) are accepted.
Request
POST /spiffe/issue-svid
Authorization: Bearer <access-token>
Content-Type: application/json
{
"uid": 1000,
"gid": 1000,
"supplemental_gids": [10, 100],
"exe_path": "/usr/bin/myapp",
"hostname": "client.example.org",
"ima_hash": "sha256:deadbeef...",
"audiences": ["service://target.example.org"],
"x509_spki_b64": "<base64-SPKI-DER>"
}
| Field | Type | Required | Description |
|---|---|---|---|
uid | u32 | yes | Unix UID of the workload, read from SO_PEERCRED on the proxy’s local socket. |
gid | u32 | yes | Unix primary GID of the workload. |
supplemental_gids | array of u32 | no | Supplemental group ID list from /proc/<pid>/status on the proxy host. Defaults to []. |
exe_path | string | no | Absolute executable path from /proc/<pid>/exe on the proxy host. When present, allows Path selectors to match. |
hostname | string | yes | Hostname of the proxy host. Used to look up IPA host group memberships (server-verified). |
ima_hash | string | no | Caller-declared executable hash in "alg:hexdigest" format. Allows ImaHash selectors to match. Supported algorithms: sha256, sha512, sha1. |
audiences | array of strings | no | JWT aud claim values for issued JWT-SVIDs. When absent or empty, defaults to [server.issuer]. |
x509_spki_b64 | string | no | Standard base64-encoded SPKI DER of an ephemeral public key generated by the proxy. When present, Ahdapa signs an X.509-SVID certificate over this key. The private key is never transmitted — only the public component reaches Ahdapa. |
Attestation behaviour:
Unlike POST /spiffe/jwt-svid, this endpoint does not restrict Uid, Gid,
SupplementalGid, or Path selectors. The proxy reads actual workload
credentials from its local socket (SO_PEERCRED, /proc/<pid>/exe,
/proc/<pid>/status) and forwards them. Ahdapa trusts these values because
the client is pre-authorized by accepted_proxies.
IPA host group membership for Hostname and Hostgroup selectors is still
resolved by Ahdapa via LDAP and cannot be forged by the caller.
If no registration entry matches the supplied workload identity, 403 is
returned. There is no fallback to a client spiffe_id — this endpoint
requires at least one matching entry.
Response
{
"jwt_svids": [
{
"spiffe_id": "spiffe://example.org/workload/myapp",
"svid": "<compact-jwt>",
"hint": ""
}
],
"x509_svids": [
{
"spiffe_id": "spiffe://example.org/workload/myapp",
"cert_chain_b64": "<base64-DER-leaf-then-CA>",
"hint": ""
}
],
"bundle": "<trust-bundle-jwks-json>",
"x509_ca_cert_b64": "<base64-DER-CA-cert>"
}
| Field | Description |
|---|---|
jwt_svids | One JWT-SVID per matched registration entry. Empty if no JWT-SVIDs were requested. |
x509_svids | One X.509-SVID per matched registration entry. Empty when x509_spki_b64 was not supplied in the request. Each element’s cert_chain_b64 is the leaf certificate DER followed by the CA certificate DER, concatenated and base64-encoded. |
bundle | Raw JWK Set JSON from /.well-known/spiffe-bundle. |
x509_ca_cert_b64 | Standard base64-encoded DER of the SPIFFE CA certificate, provided separately for convenient chain assembly. |
Error codes
| Status | Condition |
|---|---|
400 | Malformed request body or invalid ima_hash format or invalid x509_spki_b64 base64 |
401 | Missing, invalid, expired, or revoked Bearer token |
403 | Client is not using kerberos_client_auth, or its Kerberos service component is not in accepted_proxies, or no registration entries matched the workload identity |
404 | SPIFFE is not configured ([spiffe] trust_domain absent) |
503 | JWT signing key or SPIFFE CA not yet initialised on this node |
ACME Token Authority
This endpoint implements the RFC 9447 Token Authority (TA) protocol for ACME
tkauth-01 challenges. It is active only when [gssapi] is configured and
a valid GSSAPI credential is available. The endpoint URL is advertised in the
AS/OIDC discovery documents as token_authority_endpoint.
Kerberos identity binding. The constraint values carried in the authority
token are derived from the authenticated Kerberos principal, not from telephony
identifiers. This is a Kerberos-specific issuance path. The
EnhancedJWTClaimConstraints (RFC 9118) structure always carries:
mustInclude: ["sub"]— the ACME server MUST reject any PASSporT that omits thesubclaim entirely.permittedValues— always contains at minimum:subbound to the authenticated Kerberos principal name (e.g.alice@IPA.TEST)issbound to the server’s issuer URL
For host and service principals (those with a / in the local part, e.g.
host/client.ipa.test@IPA.TEST or ldap/client.ipa.test@IPA.TEST), the
server additionally performs an IPA LDAP lookup to find all hosts and services
managed by the authenticated principal (managedBy attribute). When any
managed FQDNs are found, a dns entry is added to permittedValues,
constraining which hostnames may appear in the PASSporT’s dns claim. The
principal’s own hostname is always included in the dns list (justified by
IPA’s default ACI that grants every principal write access to its own
userCertificate attribute).
For user principals (e.g. alice@IPA.TEST, no / in the local part) no
dns entry is added — the token is an identity-only binding.
An ACME server validating the token can use these constraints to confirm both the identity of the principal and the issuing authority, and to restrict which DNS identifiers the PASSporT may assert.
| Method | Path | Auth | Description |
|---|---|---|---|
POST | /at/account/{id}/token | Authorization: Negotiate (SPNEGO) | Issue an authority token JWT for the ACME account identified by {id}. |
Request
POST /at/account/{id}/token
Authorization: Negotiate <base64-SPNEGO-token>
Content-Type: application/json
{
"atc": {
"tktype": "JWTClaimConstraints",
"tkvalue": "<client-proposed-base64url-DER>",
"fingerprint": "<ACME-account-key-fingerprint>",
"ca": false
}
}
| Field | Type | Required | Description |
|---|---|---|---|
atc.tktype | string | yes | Must be "JWTClaimConstraints". Any other value returns 400. |
atc.tkvalue | string | yes | Client-proposed constraint value. Present per the RFC but ignored by the server — Ahdapa always builds the constraint from the authenticated principal. |
atc.fingerprint | string | yes | ACME account key fingerprint. Passed through verbatim into the signed token; the TA does not verify this value (per RFC 9447). |
atc.ca | bool | no | Whether the requested token is for a CA account. Passed through verbatim. Default: false. |
Response
On success, 200 OK with:
{
"token": "<compact-JWT>"
}
The JWT payload contains:
| Claim | Description |
|---|---|
iss | Server issuer URL ([server] issuer). |
exp | Expiry timestamp (access token TTL from [tokens] access_token_ttl). |
jti | Unique token identifier (<node_id>/<uuid>). |
atc.tktype | "JWTClaimConstraints" |
atc.tkvalue | Base64url-encoded DER of an EnhancedJWTClaimConstraints (RFC 9118) with mustInclude: ["sub"] and permittedValues binding sub to the Kerberos principal, iss to the server issuer URL, and (for host/service principals) dns to the IPA-managed FQDNs for that principal. |
atc.fingerprint | The fingerprint from the request. |
atc.ca | The ca flag from the request. |
The JWT is signed with the server’s active JWT signing key (same key used for
OAuth2 access tokens, algorithm from [server] jwt_signing_algorithm).
Error codes
| Status | Condition |
|---|---|
400 | Malformed request body or tktype is not "JWTClaimConstraints" |
401 | No Authorization: Negotiate header (response includes WWW-Authenticate: Negotiate) |
403 | SPNEGO token present but authentication failed |
503 | GSSAPI credential not configured ([gssapi] absent or credential acquisition failed) |
Machine-readable Identity API
Mounted under /api/identity/. These endpoints expose user and group identity
data to machine clients (primarily SSSD). All endpoints require an access token
with the directory.read scope in the Authorization: Bearer header. See
Identity API for the full reference and SSSD integration details.
| Method | Path | Description |
|---|---|---|
GET | /api/identity/users | Phase 1 user search by username. Requires ?username= and ?exact=true. |
GET | /api/identity/users/{id}/groups | Phase 2 group membership for a user. {id} may be a short uid or fully-qualified UPN. |
GET | /api/identity/groups | Phase 1 group search by name. Requires ?search= and ?exact=true. |
GET | /api/identity/groups/{name}/members | Phase 2 group members list. Returns user objects (id + username only). |
Static assets
| Path | Description |
|---|---|
/ui/ | Management WebUI (Preact SPA). Only present when webui.static_dir is configured. |