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

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/.

MethodPathDescription
GET/.well-known/openid-configurationOIDC Provider Metadata (RFC 8414 / OIDC Core §4)
GET/.well-known/oauth-authorization-serverOAuth2 Authorization Server Metadata (RFC 8414)
GET/.well-known/openid-federationOIDC Federation 1.0 Entity Statement

Core OAuth2 / OIDC

MethodPathRFC / SpecDescription
GET POST/authorizeRFC 6749 §4.1, RFC 7636, RFC 9700 §4.2.4Authorization 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/tokenRFC 6749 §5.1, §4.1.3Token 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/revokeRFC 7009Token revocation. Accepts an access token or refresh token. Revoking a refresh token invalidates its entire family.
POST/introspectRFC 7662Token introspection. Returns active/inactive status and claims for a presented token.
GET POST/userinfoOIDC Core §5.3UserInfo endpoint. Returns claims for the authenticated user from the Bearer token.
GET/jwksRFC 7517JSON Web Key Set — public keys used to verify tokens. Rotated via the admin API.
POST/parRFC 9126Pushed Authorization Request. Accepts authorization parameters and returns a request_uri for use in /authorize.
POST/device_authorizationRFC 8628Device Authorization endpoint. Issues a device_code and user_code for device-flow clients.
GET POST/deviceRFC 8628Device verification page. Users enter their user_code here to authorize a device.
POST/registerRFC 7591Dynamic 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.

MethodPathDescription
GET/loginRedirect to the SPA login page at /ui/auth/login.
GET/ui/auth/loginServe 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/loginSubmit username and password credentials. On success, issues a session cookie. On PAM PasswordExpired, redirects to /login/change-password.
GET/login/change-passwordRender the change-password page. Receives ?username= and ?next= query parameters. Only reachable via redirect from POST /login. Requires the pam feature.
POST/login/change-passwordSubmit 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].

MethodPathDescription
POST/api/auth/passkey/beginBegin passkey authentication. Returns a WebAuthn PublicKeyCredentialRequestOptions challenge.
POST/api/auth/passkey/completeComplete passkey authentication. Verifies the authenticator assertion and issues a session cookie.
POST/api/auth/passkey/register/beginBegin passkey registration for the current user. Requires a session.
POST/api/auth/passkey/register/completeComplete passkey registration. Stores the new credential in FreeIPA.
GET/api/auth/passkeysList 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.

MethodPathDescription
POST/api/auth/loginJSON login endpoint for the WebUI. Accepts {"username":"…","password":"…"}.
POST/api/auth/otpJSON OTP login: {"username":"…","password":"…","otp_code":"…"}. Rate-limited. Issues a session cookie on success. No authentication required.
POST/api/auth/logoutInvalidate the current session cookie.
GET/api/auth/meReturn the username and groups of the current session.
GET/api/auth/profileReturn the full user profile (display name, email, groups) from LDAP.
GET/api/auth/infoReturn 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/providersList configured upstream identity providers (for the WebUI login chooser). No authentication required.
GET/api/auth/federated-hintReturn 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/consentRender the OAuth2 consent page for the current pending authorization.
POST/api/auth/consentSubmit the consent decision (approve / deny).
GET/api/auth/deviceLook up a pending device-flow request by user_code. Requires a session.
POST/api/auth/deviceApprove 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

MethodPathDescription
GET/api/me/otp-tokensList 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-tokensCreate 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.

MethodPathDescription
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.

MethodPathAuthDescription
GET/.well-known/spiffe-bundleNoneSPIFFE 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-svidBearer tokenExchange 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-svidBearer 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.

MethodPathAuthDescription
POST/spiffe/jwt-svidBearer access tokenExchange 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..."
}
FieldTypeRequiredDescription
audiencearray of stringsnoJWT 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.
hostnamestringnoCaller-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_hashstringnoCaller-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:

  1. 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).
  2. A remote AttestationContext is built with UID=u32::MAX, GID=u32::MAX (sentinel values), the declared hostname, the LDAP-resolved host groups, and the parsed ima_hash (if provided).
  3. All live registration entries are evaluated; each matching entry produces one JWT-SVID with that entry’s SPIFFE ID.
  4. If no entries match, the handler falls back to the client’s registered spiffe_id (single SVID).
  5. If neither path yields a SPIFFE ID, 403 Forbidden is 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

StatusCondition
400Malformed request body
401Missing, invalid, expired, or revoked Bearer token
403Token is valid but neither remote attestation nor client spiffe_id yielded a SPIFFE ID
404SPIFFE is not configured ([spiffe] trust_domain absent)
503JWT 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.

MethodPathAuthDescription
POST/spiffe/issue-svidBearer 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:

  1. The OAuth2 client whose token is presented must have token_endpoint_auth_method = "kerberos_client_auth". Any other authentication method returns 403 Forbidden.
  2. The Kerberos principal stored on the client must have a service component (the part before the first /) that appears in [spiffe] accepted_proxies on 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>"
}
FieldTypeRequiredDescription
uidu32yesUnix UID of the workload, read from SO_PEERCRED on the proxy’s local socket.
gidu32yesUnix primary GID of the workload.
supplemental_gidsarray of u32noSupplemental group ID list from /proc/<pid>/status on the proxy host. Defaults to [].
exe_pathstringnoAbsolute executable path from /proc/<pid>/exe on the proxy host. When present, allows Path selectors to match.
hostnamestringyesHostname of the proxy host. Used to look up IPA host group memberships (server-verified).
ima_hashstringnoCaller-declared executable hash in "alg:hexdigest" format. Allows ImaHash selectors to match. Supported algorithms: sha256, sha512, sha1.
audiencesarray of stringsnoJWT aud claim values for issued JWT-SVIDs. When absent or empty, defaults to [server.issuer].
x509_spki_b64stringnoStandard 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>"
}
FieldDescription
jwt_svidsOne JWT-SVID per matched registration entry. Empty if no JWT-SVIDs were requested.
x509_svidsOne 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.
bundleRaw JWK Set JSON from /.well-known/spiffe-bundle.
x509_ca_cert_b64Standard base64-encoded DER of the SPIFFE CA certificate, provided separately for convenient chain assembly.

Error codes

StatusCondition
400Malformed request body or invalid ima_hash format or invalid x509_spki_b64 base64
401Missing, invalid, expired, or revoked Bearer token
403Client is not using kerberos_client_auth, or its Kerberos service component is not in accepted_proxies, or no registration entries matched the workload identity
404SPIFFE is not configured ([spiffe] trust_domain absent)
503JWT 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 the sub claim entirely.
  • permittedValues — always contains at minimum:
    • sub bound to the authenticated Kerberos principal name (e.g. alice@IPA.TEST)
    • iss bound 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.

MethodPathAuthDescription
POST/at/account/{id}/tokenAuthorization: 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
  }
}
FieldTypeRequiredDescription
atc.tktypestringyesMust be "JWTClaimConstraints". Any other value returns 400.
atc.tkvaluestringyesClient-proposed constraint value. Present per the RFC but ignored by the server — Ahdapa always builds the constraint from the authenticated principal.
atc.fingerprintstringyesACME account key fingerprint. Passed through verbatim into the signed token; the TA does not verify this value (per RFC 9447).
atc.caboolnoWhether 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:

ClaimDescription
issServer issuer URL ([server] issuer).
expExpiry timestamp (access token TTL from [tokens] access_token_ttl).
jtiUnique token identifier (<node_id>/<uuid>).
atc.tktype"JWTClaimConstraints"
atc.tkvalueBase64url-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.fingerprintThe fingerprint from the request.
atc.caThe 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

StatusCondition
400Malformed request body or tktype is not "JWTClaimConstraints"
401No Authorization: Negotiate header (response includes WWW-Authenticate: Negotiate)
403SPNEGO token present but authentication failed
503GSSAPI 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.

MethodPathDescription
GET/api/identity/usersPhase 1 user search by username. Requires ?username= and ?exact=true.
GET/api/identity/users/{id}/groupsPhase 2 group membership for a user. {id} may be a short uid or fully-qualified UPN.
GET/api/identity/groupsPhase 1 group search by name. Requires ?search= and ?exact=true.
GET/api/identity/groups/{name}/membersPhase 2 group members list. Returns user objects (id + username only).

Static assets

PathDescription
/ui/Management WebUI (Preact SPA). Only present when webui.static_dir is configured.