Admin API
The Admin API provides endpoints for administering the SympAuthy authorization server, including client management, user administration, access control, and monitoring. This API is intended for operators and internal tooling, not for end-user-facing applications.
All Admin API endpoints are under /api/v1/admin/ and require authentication with appropriate admin scopes.
Admin Environment
SympAuthy provides a dedicated admin Micronaut environment that pre-configures everything needed to use the Admin API:
- An
adminaudience that admin scopes are bound to - All admin scopes listed in the Admin Scopes table below, restricted to the
adminaudience - A default
adminclient in theadminaudience with all admin scopes in itsallowed-scopes
To activate the admin environment, include admin in the MICRONAUT_ENVIRONMENTS variable:
MICRONAUT_ENVIRONMENTS=default,by-mail,adminThe default admin client is a public client that uses PKCE instead of a client secret. Everything is ready out of the box — no secret to configure.
You can also configure admin access manually without using the
adminenvironment. Setadmin.audienceto an existing audience, add the desired admin scopes to a client'sallowed-scopesin the configuration, and ensure the client belongs to the same audience. Mark the client as a public client to use PKCE. This is useful if you need multiple admin clients with different permission levels.
Admin Scopes
Admin scopes follow the naming convention admin:{domain}:{action}, providing fine-grained control so operators can grant only the minimum necessary privileges.
| Scope | Description |
|---|---|
admin:config:read | List and view configuration resources (audiences, clients, claims, scopes) |
admin:consent:read | View consents |
admin:consent:write | Revoke consents, force logout |
admin:invitations:read | List and view invitations |
admin:invitations:write | Create and revoke invitations |
admin:users:read | List and view users |
admin:users:write | Create, update, disable, enable users |
admin:users:delete | Delete users (separated for GDPR sensitivity) |
The admin:users:delete scope is intentionally separated from admin:users:write because user deletion is an irreversible operation with GDPR implications and should require explicit authorization.
Authentication
All Admin API endpoints require authentication using an OAuth 2.1 access token obtained via the Client Credentials flow with PKCE. The default admin client is a public client — it authenticates using a code verifier instead of a client secret.
Obtaining an Access Token
To authenticate with the Admin API, you must first obtain an access token using the OAuth 2.1 Client Credentials grant with PKCE:
Step 1: Generate a PKCE code verifier and challenge
Before making the token request, generate a random code_verifier and compute the challenge:
code_challenge = BASE64URL(SHA256(code_verifier))Step 2: Request an access token from the Token Endpoint
Endpoint: /api/oauth2/token
Method: POST
Request Format:
POST /api/oauth2/token
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_id=YOUR_ADMIN_CLIENT_ID
&code_verifier=YOUR_CODE_VERIFIER
&code_challenge=YOUR_CODE_CHALLENGE
&code_challenge_method=S256When using the
adminMicronaut environment, the default admin client ID is pre-configured. No client secret is needed — PKCE secures the exchange.
Response Format:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600
}Step 3: Use the access token in Admin API requests
Include the access token in the Authorization header:
GET /api/v1/admin/users
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...Authorization
Each Admin API endpoint requires a specific admin scope. The access token must include the scope required by the endpoint being called.
- If the token is missing or invalid: 401 Unauthorized
- If the token is valid but lacks the required scope: 403 Forbidden
401 Response Example:
{
"error": "unauthorized",
"error_description": "Missing or invalid access token."
}403 Response Example:
{
"error": "forbidden",
"error_description": "The access token does not include the required scope: admin:users:read"
}The required scope for each endpoint is documented in the Endpoints section below.
Endpoints
Work in progress — Client Management, Claim Management, Scope Management, and Audience Management endpoints are implemented. The remaining endpoints below are planned but not yet implemented. The paths and response formats shown are preliminary and may change. See GitHub issue #109 for progress.
Client Management
Endpoints for viewing configured client applications. Since clients are defined in configuration files (not in a database), these endpoints expose them as read-only resources. Client secrets are never included in responses. Requires the admin:config:read scope.
List Clients
Path: /api/v1/admin/clients
Method: GET
Authentication: Bearer token with admin:config:read scope
Purpose: Retrieves a paginated list of all configured client applications.
Query Parameters:
page(optional): Zero-indexed page number (default:0)size(optional): Number of results per page (default:20)
Response Format:
{
"clients": [
{
"client_id": "my-app",
"type": "public",
"allowed_scopes": [
"openid",
"profile"
],
"default_scopes": [
"openid"
],
"allowed_redirect_uris": [
"https://my-app.com/callback"
]
}
],
"page": 0,
"size": 20,
"total": 1
}Properties:
clients: Array of client recordsclient_id: Unique identifier of the client, as defined in configurationtype: Type of the client as defined by the OAuth 2.1 specification. Possible values:"public"|"confidential"allowed_scopes: Scopes the client is allowed to requestdefault_scopes: Scopes granted by default when the client does not explicitly request anyallowed_redirect_uris: Redirect URIs the client is allowed to use during authorization
page: Current page numbersize: Number of results per pagetotal: Total number of clients
Use Cases:
- Admin dashboard listing all registered clients and their permissions
- Verifying which scopes and redirect URIs are configured for a specific client
- Auditing client configurations without accessing configuration files directly
Get Client Details
Path: /api/v1/admin/clients/{client_id}
Method: GET
Authentication: Bearer token with admin:config:read scope
Purpose: Retrieves details for a specific client.
Path Parameters:
client_id: Unique identifier of the client
Response Format:
200 OK:
{
"client_id": "my-app",
"type": "public",
"allowed_scopes": [
"openid",
"profile"
],
"default_scopes": [
"openid"
],
"allowed_redirect_uris": [
"https://my-app.com/callback"
]
}404 Not Found:
{
"error": "not_found",
"error_description": "No client found with id: my-app"
}Properties:
client_id: Unique identifier of the client, as defined in configurationtype: Type of the client as defined by the OAuth 2.1 specification. Possible values:"public"|"confidential"allowed_scopes: Scopes the client is allowed to requestdefault_scopes: Scopes granted by default when the client does not explicitly request anyallowed_redirect_uris: Redirect URIs the client is allowed to use during authorization
Use Cases:
- Admin dashboard listing all registered clients and their permissions
- Verifying which scopes and redirect URIs are configured for a specific client
- Auditing client configurations without accessing configuration files directly
Claim Management
Endpoints for viewing configured claims. Since claims are defined in configuration files (not in a database), these endpoints expose them as read-only resources — following the same pattern as Client Management. Both OpenID Connect and custom claims are returned. Requires the admin:config:read scope.
List Claims
Path: /api/v1/admin/claims
Method: GET
Authentication: Bearer token with admin:config:read scope
Purpose: Retrieves a paginated list of all configured claims (OpenID Connect and custom).
Query Parameters:
page(optional): Zero-indexed page number (default:0)size(optional): Number of results per page (default:20)enabled(optional): Filter by enabled status (true,false)required(optional): Filter by required status (true,false)origin(optional): Filter by origin (openidfor OpenID Connect claims,customfor operator-defined claims)
Response Format:
{
"claims": [
{
"id": "email",
"type": "string",
"origin": "openid",
"enabled": true,
"required": true,
"identifier": true,
"allowed_values": null,
"group": null
},
{
"id": "name",
"type": "string",
"origin": "openid",
"enabled": true,
"required": false,
"identifier": false,
"allowed_values": null,
"group": "profile"
},
{
"id": "custom_department",
"type": "string",
"origin": "custom",
"enabled": true,
"required": false,
"identifier": false,
"allowed_values": [
"Engineering",
"Marketing",
"Sales"
],
"group": null
}
],
"page": 0,
"size": 20,
"total": 3
}Properties:
claims: Array of claim recordsid: Unique claim identifier, as defined in configurationtype: Data type expected for this claim (string,number, ordate)origin: Where the claim is defined. Possible values:"openid"(OpenID Connect specification) |"custom"(defined by the operator in configuration)enabled: Whether collection is enabled for this claimrequired: Whether the end-user must provide this claim to complete an authorization flowidentifier: Whether this claim is configured as an identifier claim, used for password login and cross-provider account mergingallowed_values: Array of accepted values, ornullif any value is accepted (no restriction)group: Grouping identifier (e.g.,"profile","address"), ornullif the claim belongs to no group
page: Current page numbersize: Number of results per pagetotal: Total number of claims
Use Cases:
- Admin dashboard displaying all configured claims and their settings
- Auditing which claims are enabled and required without accessing configuration files
- Reviewing allowed values for claims with restricted inputs
Scope Management
Endpoints for viewing configured scopes. Since scopes are defined in configuration files or by SympAuthy itself (not in a database), these endpoints expose them as read-only resources — following the same pattern as Client Management and Claim Management. All three scope types (consentable, grantable, client) are returned. Requires the admin:config:read scope.
List Scopes
Path: /api/v1/admin/scopes
Method: GET
Authentication: Bearer token with admin:config:read scope
Purpose: Retrieves a paginated list of all configured scopes (OpenID Connect and custom, across all three types).
Query Parameters:
page(optional): Zero-indexed page number (default:0)size(optional): Number of results per page (default:20)type(optional): Filter by scope type (consentable,grantable,client)enabled(optional): Filter by enabled status (true,false)
Response Format:
{
"scopes": [
{
"id": "openid",
"type": "grantable",
"origin": "openid",
"enabled": true
},
{
"id": "profile",
"type": "consentable",
"origin": "openid",
"enabled": true,
"claims": [
"name",
"family_name",
"given_name",
"middle_name",
"nickname",
"preferred_username",
"picture",
"website",
"gender",
"birthdate",
"zoneinfo",
"locale",
"updated_at"
]
},
{
"id": "admin:users:read",
"type": "grantable",
"origin": "system",
"enabled": true
},
{
"id": "users:read",
"type": "client",
"origin": "system",
"enabled": true
}
],
"page": 0,
"size": 20,
"total": 4
}Properties:
scopes: Array of scope recordsid: Unique scope identifiertype: Scope type. Possible values:"consentable"|"grantable"|"client". See Scope for the meaning of each typeorigin: Where the scope is defined. Possible values:"oauth2"(OAuth 2 specification) |"openid"(OpenID Connect specification) |"system"(defined by SympAuthy) |"custom"(defined by the operator in configuration)enabled: Whether the scope is enabledclaims(consentable scopes only): Array of claim identifiers protected by this scope. Omitted for grantable and client scopes
page: Current page numbersize: Number of results per pagetotal: Total number of scopes
Use Cases:
- Admin dashboard displaying all available scopes and their types
- Auditing which scopes are enabled and how they are categorized
- Reviewing which claims are protected by each consentable scope
- Filtering scopes by type to inspect admin, client, or user-facing permissions separately
Audience Management
Endpoints for viewing configured audiences. Since audiences are defined in configuration files (not in a database), these endpoints expose them as read-only resources — following the same pattern as Client Management, Claim Management, and Scope Management. Requires the admin:config:read scope.
List Audiences
Path: /api/v1/admin/audiences
Method: GET
Authentication: Bearer token with admin:config:read scope
Purpose: Retrieves a paginated list of all configured audiences.
Query Parameters:
page(optional): Zero-indexed page number (default:0)size(optional): Number of results per page (default:20)
Response Format:
{
"audiences": [
{
"audience_id": "my-app",
"token_audience": "my-app"
}
],
"page": 0,
"size": 20,
"total": 1
}Properties:
audiences: Array of audience recordsaudience_id: Unique identifier of the audience, as defined in the configurationtoken_audience: Value used as theaudclaim in access and refresh tokens issued for clients belonging to this audience. Defaults to the audience identifier when not explicitly configured
page: Current page numbersize: Number of results per pagetotal: Total number of audiences
Use Cases:
- Admin dashboard listing all configured audiences and their token audience values
- Verifying which
audclaim value will appear in tokens for a given audience - Auditing audience configurations without accessing configuration files directly
Get Audience Details
Path: /api/v1/admin/audiences/{audienceId}
Method: GET
Authentication: Bearer token with admin:config:read scope
Purpose: Retrieves details for a specific audience.
Path Parameters:
audienceId: Unique identifier of the audience
Response Format:
200 OK:
{
"audience_id": "my-app",
"token_audience": "my-app"
}404 Not Found:
{
"error": "not_found",
"error_description": "No audience found with id: my-app"
}Properties:
audience_id: Unique identifier of the audience, as defined in the configurationtoken_audience: Value used as theaudclaim in access and refresh tokens issued for clients belonging to this audience. Defaults to the audience identifier when not explicitly configured
Use Cases:
- Verify the token audience value for a specific audience in an admin dashboard
- Confirm an audience exists and inspect its configuration
- Look up the
audclaim value that will appear in tokens issued for a specific audience
User Management
Endpoints for managing end-user accounts. Different operations require different scopes: admin:users:read for read operations, admin:users:write for modifications, and admin:users:delete for deletion.
Create User
Path: /api/v1/admin/users
Method: POST
Authentication: Bearer token with admin:users:write scope
Purpose: Creates a new user account. Useful for bulk provisioning and user migrations.
Request Format:
{
"claims": {
"email": "user@example.com",
"name": "Jane Doe",
"given_name": "Jane",
"family_name": "Doe"
},
"password": "initial-password"
}Response Format:
{
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"claims": {
"email": "user@example.com",
"name": "Jane Doe",
"given_name": "Jane",
"family_name": "Doe"
},
"status": "enabled",
"created_at": "2026-03-06T10:00:00Z"
}Properties:
user_id: Unique identifier assigned to the new userclaims: Object containing the user's claimsstatus: Account status (enabled)created_at: ISO 8601 timestamp (UTC) when the account was created
Use Cases:
- Bulk user provisioning from an external system
- User migration from another identity provider
- Creating service accounts
List Users
Path: /api/v1/admin/users
Method: GET
Authentication: Bearer token with admin:users:read scope
Purpose: Retrieves a paginated list of users. Supports filtering by status, searching by claim values, selecting which claims to include, and sorting.
Query Parameters:
page(optional): Zero-indexed page number (default:0)size(optional): Number of results per page (default:20)status(optional): Filter by account status (enabled,disabled)claims(optional): Comma-separated claim IDs to include in the response (default: all enabled claims)q(optional): Partial, case-insensitive search across all enabled claim values{claim_id}(optional): Exact-match filter on a specific claim (e.g.,?email=jane@example.com)sort(optional): Property to sort by:created_at,status, or any enabled claim IDorder(optional): Sort direction —ascordesc(default:asc)
Reserved parameter names
The names page, size, status, claims, q, sort, and order are reserved and cannot be used as claim IDs for filtering.
Response Format:
{
"users": [
{
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"claims": {
"email": "jane@example.com",
"name": "Jane Doe"
},
"status": "enabled",
"created_at": "2026-01-15T14:30:00Z"
}
],
"page": 0,
"size": 20,
"total": 42
}Properties:
users: Array of user recordsuser_id: Unique identifier of the userclaims: Object containing the user's claim values. By default includes all enabled claims; use theclaimsquery parameter to select specific claims.status: Account status (enabledordisabled)created_at: ISO 8601 timestamp (UTC) when the account was created
page: Current page numbersize: Number of results per pagetotal: Total number of users matching the query
Errors:
Returns 400 Bad Request with error code invalid_claim when:
claimscontains a disabled or unknown claim IDsortreferences a disabled or unknown claim ID- A claim filter query parameter references a disabled or unknown claim ID
{
"error": "invalid_claim",
"error_description": "Unknown or disabled claim: department"
}Use Cases:
- Display user lists with profile details in an admin dashboard
- Search for users by name or email
- Sort users by a specific claim value (e.g., alphabetically by name)
- Filter users by a specific claim value (e.g., all users in a department)
Get User
Path: /api/v1/admin/users/{user_id}
Method: GET
Authentication: Bearer token with admin:users:read scope
Purpose: Retrieves the account status, metadata, and identifier claim values for a specific user.
Path Parameters:
user_id: Unique identifier of the user
Response Format:
{
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "enabled",
"created_at": "2026-01-15T14:30:00Z",
"identifier_claims": {
"email": "jane@example.com"
}
}Properties:
user_id: Unique identifier of the userstatus: Account status (enabledordisabled)created_at: ISO 8601 timestamp (UTC) when the account was createdidentifier_claims: Object containing the user's identifier claim values as key/value pairs. Only claims configured as identifiers are included.
Use Cases:
- Check a user's account status in an admin dashboard
- Verify whether a user account exists and is active
- Display a user summary with their identifying information (e.g., email) without loading full claim data
List User Claims
Path: /api/v1/admin/users/{user_id}/claims
Method: GET
Authentication: Bearer token with admin:users:read scope
Purpose: Retrieves a paginated list of claim values for a specific user, with claim definition metadata. Only claims enabled in the configuration are returned. OpenID *_verified claims (e.g., email_verified, phone_number_verified) are excluded — their status is represented by the verified_at field on the parent claim.
Path Parameters:
user_id: Unique identifier of the user
Query Parameters:
page(optional): Zero-indexed page number (default:0)size(optional): Number of results per page (default:20)claim_id(optional): Filter by specific claim ID (e.g.,?claim_id=email)identifier(optional): Filter by identifier status (true,false)required(optional): Filter by required status (true,false)collected(optional): Filter by whether a value has been collected (true,false)verified(optional): Filter by whether the claim has been verified (true,false)origin(optional): Filter by origin (openidfor OpenID Connect claims,customfor operator-defined claims)
Response Format:
{
"claims": [
{
"claim_id": "email",
"value": "jane@example.com",
"type": "string",
"origin": "openid",
"required": true,
"identifier": true,
"group": null,
"collected_at": "2026-01-15T14:30:00Z",
"verified_at": "2026-01-15T14:35:00Z"
},
{
"claim_id": "name",
"value": "Jane Doe",
"type": "string",
"origin": "openid",
"required": false,
"identifier": false,
"group": "profile",
"collected_at": "2026-01-15T14:30:00Z",
"verified_at": null
},
{
"claim_id": "custom_department",
"value": null,
"type": "string",
"origin": "custom",
"required": false,
"identifier": false,
"group": null,
"collected_at": null,
"verified_at": null
}
],
"page": 0,
"size": 20,
"total": 3
}Properties:
claims: Array of claim recordsclaim_id: Unique claim identifier, as defined in configurationvalue: The user's value for this claim, ornullif not yet providedtype: Data type (string,number, ordate)origin: Where the claim is defined. Possible values:"openid"(OpenID Connect specification) |"custom"(defined by the operator in configuration)required: Whether the end-user must provide this claimidentifier: Whether this claim is configured as an identifier claimgroup: Optional grouping identifier (e.g.,"profile","address"), ornullcollected_at: ISO 8601 timestamp (UTC) when the value was collected, ornullverified_at: ISO 8601 timestamp (UTC) when the value was verified, ornull
page: Current page numbersize: Number of results per pagetotal: Total number of claims matching the filters
Use Cases:
- View a user's profile data in an admin dashboard
- Audit which required claims are missing (
?collected=false&required=true) - Check which claims have been verified (
?verified=true) - Find unverified identifier claims (
?identifier=true&verified=false) - List only custom claims (
?origin=custom)
Update User
Path: /api/v1/admin/users/{user_id}
Method: PATCH
Authentication: Bearer token with admin:users:write scope
Purpose: Updates claims for a specific user. Only the provided claims are modified; omitted claims remain unchanged.
Path Parameters:
user_id: Unique identifier of the user
Request Format:
{
"claims": {
"name": "Jane Smith",
"family_name": "Smith",
"custom_department": "Engineering"
}
}Response Format:
{
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"claims": {
"email": "user@example.com",
"email_verified": true,
"name": "Jane Smith",
"given_name": "Jane",
"family_name": "Smith",
"custom_department": "Engineering"
},
"status": "enabled",
"created_at": "2026-01-15T14:30:00Z"
}Properties:
user_id: Unique identifier of the userclaims: Object containing all of the user's claims after the updatestatus: Account statuscreated_at: ISO 8601 timestamp (UTC) when the account was created
Use Cases:
- Update user attributes from an external HR system
- Correct user profile information
- Manage custom claims for application-specific metadata
Disable User
Path: /api/v1/admin/users/{user_id}/disable
Method: POST
Authentication: Bearer token with admin:users:write scope
Purpose: Disables a user account. A disabled user cannot authenticate but their data is preserved.
Path Parameters:
user_id: Unique identifier of the user
Response Format:
{
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "disabled"
}Use Cases:
- Temporarily suspend a user account during a security investigation
- Offboard employees while retaining their data for audit purposes
- Comply with account suspension requests
Enable User
Path: /api/v1/admin/users/{user_id}/enable
Method: POST
Authentication: Bearer token with admin:users:write scope
Purpose: Re-enables a previously disabled user account.
Path Parameters:
user_id: Unique identifier of the user
Response Format:
{
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "enabled"
}Use Cases:
- Restore access after a security investigation concludes
- Re-onboard a returning employee
- Resolve accidental account suspensions
Delete User
Path: /api/v1/admin/users/{user_id}
Method: DELETE
Authentication: Bearer token with admin:users:delete scope
Purpose: Permanently deletes a user account and all associated data. This operation is irreversible.
Path Parameters:
user_id: Unique identifier of the user
Response Format:
{
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"deleted": true
}Important Notes:
- This operation is irreversible — all user data, claims, sessions, and consents are permanently removed
- Requires the dedicated
admin:users:deletescope, which is intentionally separated fromadmin:users:write - Intended for GDPR right-to-erasure compliance
Use Cases:
- Fulfill GDPR deletion requests (right to erasure)
- Remove accounts during data cleanup operations
- Complete user offboarding with full data removal
Reset Password
Path: /api/v1/admin/users/{user_id}/reset-password
Method: POST
Authentication: Bearer token with admin:users:write scope
Purpose: Administratively resets the password for a user account.
Path Parameters:
user_id: Unique identifier of the user
Request Format:
{
"new_password": "new-secure-password"
}Response Format:
{
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"password_reset": true
}Use Cases:
- Help users locked out of their accounts
- Enforce password changes during security incidents
- Set initial passwords during bulk user provisioning
Force Logout
Path: /api/v1/admin/users/{user_id}/logout
Method: POST
Authentication: Bearer token with admin:consent:write scope
Purpose: Revokes all tokens for a specific user, forcing them to re-authenticate.
Path Parameters:
user_id: Unique identifier of the user
Response Format:
{
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"tokens_revoked": 3
}Properties:
user_id: Unique identifier of the usertokens_revoked: Number of active tokens that were revoked
Use Cases:
- Respond to a compromised account by terminating all sessions
- Enforce re-authentication after a password reset
- Remove access for a departing employee immediately
Force Client Logout
Path: /api/v1/admin/users/{user_id}/logout/{client_id}
Method: POST
Authentication: Bearer token with admin:consent:write scope
Purpose: Revokes all tokens for a specific user on a specific client application, forcing them to re-authenticate on that client only.
Path Parameters:
user_id: Unique identifier of the userclient_id: Unique identifier of the client application
Response Format:
{
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"client_id": "my-client-app",
"tokens_revoked": 2
}Properties:
user_id: Unique identifier of the userclient_id: Identifier of the client application whose tokens were revokedtokens_revoked: Number of active tokens that were revoked for the specified client
Use Cases:
- Revoke access for a user on a specific application without affecting their other sessions
- Respond to a client-specific security incident
- Remove access to a particular service for a departing team member
Provider Links
Endpoints for viewing and managing the links between end-user accounts and external identity providers. Requires admin:users:read for read operations and admin:users:write for modifications.
List User Provider Links
Path: /api/v1/admin/users/{user_id}/providers
Method: GET
Authentication: Bearer token with admin:users:read scope
Purpose: Retrieves a paginated list of all external identity providers linked to a specific user account.
Path Parameters:
user_id: Unique identifier of the user
Query Parameters:
page(optional): Zero-indexed page number (default:0)size(optional): Number of results per page (default:20)
Response Format:
200 OK:
{
"providers": [
{
"provider_id": "discord",
"subject": "123456789012345678",
"linked_at": "2026-01-15T14:30:00Z"
},
{
"provider_id": "google",
"subject": "109876543210",
"linked_at": "2026-02-01T10:00:00Z"
}
],
"page": 0,
"size": 20,
"total": 2
}404 Not Found:
{
"error": "not_found",
"error_description": "No user found with id: 550e8400-e29b-41d4-a716-446655440000"
}Properties:
providers: Array of provider link recordsprovider_id: Identifier of the external provider, as defined in configurationsubject: The user's unique identifier at the providerlinked_at: ISO 8601 timestamp (UTC) when the provider was linked to this account
page: Current page numbersize: Number of results per pagetotal: Total number of linked providers
Use Cases:
- View which external providers a user has linked in an admin dashboard
- Investigate authentication issues related to a specific provider
- Audit provider links for security reviews
Unlink Provider
Path: /api/v1/admin/users/{user_id}/providers/{provider_id}
Method: DELETE
Authentication: Bearer token with admin:users:write scope
Purpose: Removes the link between a user account and an external identity provider. The user will no longer be able to authenticate through this provider until they re-link it via the authentication flow. Returns 404 if no link exists for the user and provider pair.
Path Parameters:
user_id: Unique identifier of the userprovider_id: Identifier of the provider to unlink
Response Format:
200 OK:
{
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"provider_id": "discord",
"unlinked": true
}404 Not Found:
{
"error": "not_found",
"error_description": "No provider link found for user 550e8400-e29b-41d4-a716-446655440000 and provider: discord"
}Properties:
user_id: Unique identifier of the userprovider_id: Identifier of the provider that was unlinkedunlinked: Confirmation that the provider was unlinked
Use Cases:
- Disconnect a compromised provider account from a user
- Clean up provider links during account maintenance
- Respond to user requests to remove a linked provider
Access Control
Endpoints for viewing and managing end-user consents. Requires the admin:consent:read scope for read operations and admin:consent:write for modifications.
List User Consents
Path: /api/v1/admin/users/{user_id}/consents
Method: GET
Authentication: Bearer token with admin:consent:read scope
Purpose: Retrieves all active consents granted by a specific user, grouped by audience.
Path Parameters:
user_id: Unique identifier of the user
Query Parameters:
page(optional): Zero-indexed page number (default:0)size(optional): Number of results per page (default:20)
Response Format:
{
"consents": [
{
"audience_id": "my-app",
"prompted_by_client_id": "my-web-app",
"scopes": [
"profile",
"email"
],
"consented_at": "2026-01-15T14:30:00Z"
},
{
"audience_id": "backoffice",
"prompted_by_client_id": "backoffice-app",
"scopes": [
"email"
],
"consented_at": "2026-02-20T09:15:30Z"
}
],
"page": 0,
"size": 20,
"total": 2
}Properties:
consents: Array of active consent recordsaudience_id: Identifier of the audience that received consentprompted_by_client_id: Identifier of the client that originally prompted consent (kept for audit)scopes: List of scopes the user has consented to for this audienceconsented_at: ISO 8601 timestamp (UTC) when consent was granted
page: Current page numbersize: Current page sizetotal: Total number of active consents for this user
Use Cases:
- Audit which audiences a user has authorized
- Review consent history for compliance reporting
- Investigate user data access for privacy requests
Revoke User Consent
Path: /api/v1/admin/users/{user_id}/consents/{audience_id}
Method: DELETE
Authentication: Bearer token with admin:consent:write scope
Purpose: Revokes the active consent granted by a user to a specific audience. All clients in the audience will no longer be able to access the user's data until the user re-authorizes. Returns 404 if no active consent exists for the user and audience pair.
Path Parameters:
user_id: Unique identifier of the useraudience_id: Identifier of the audience whose consent should be revoked
Response Format:
{
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"audience_id": "my-app",
"revoked": true
}Revocation behavior:
When a consent is revoked through this endpoint:
- The consent is marked as revoked (
revoked_by = ADMIN) with the administrator's identifier. - All refresh tokens for the user across all clients in the audience are immediately invalidated.
- As a safety net, subsequent token refresh attempts also verify that a valid consent exists — so even if a refresh token was missed, it cannot be used.
Existing access tokens for clients in the audience remain valid until they expire naturally (typically minutes), but no new tokens can be obtained.
Use Cases:
- Revoke access for a decommissioned audience
- Respond to user requests to disconnect an application
- Enforce access policies during security incidents
Invitation Management
Endpoints for creating, viewing, and revoking invitations. Invitations allow invitation-only registration for audiences where open sign-up is disabled. Requires admin:invitations:read for read operations and admin:invitations:write for creation and revocation.
The admin API can see and manage all invitations regardless of who created them (admin or client).
Create Invitation
Path: /api/v1/admin/invitations
Method: POST
Authentication: Bearer token with admin:invitations:write scope
Purpose: Creates a single-use invitation for a specific audience. The invitation token is returned only in this response — it cannot be retrieved later.
Request Format:
{
"audience": "default",
"expires_at": "2026-04-15T00:00:00Z",
"claims": {
"custom_department": "Engineering",
"role": "admin"
},
"note": "Onboarding Jane from the Engineering team"
}Properties:
audience(required): The audience the invitation is bound to. When the invitation is redeemed, the requesting client must belong to this audience.expires_at(optional): Expiration date as an ISO 8601 timestamp (UTC). Defaults tonow + default-expiration. Capped atnow + max-expiration. See advanced configuration for these values.claims(optional): Custom claim values to pre-set on the user's account upon registration. Only custom claims are accepted — OpenID Connect claims must come from the user. Unlike the Client API, admin invitations skip the claim ACL check — any enabled custom claim can be pre-assigned.note(optional): Admin-only note attached to the invitation.
Response Format:
201 Created:
{
"invitation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"token": "dGhpcyBpcyBhIHNlY3VyZSByYW5kb20gdG9rZW4",
"audience": "default",
"status": "pending",
"claims": {
"custom_department": "Engineering",
"role": "admin"
},
"note": "Onboarding Jane from the Engineering team",
"created_at": "2026-03-28T10:00:00Z",
"expires_at": "2026-04-04T10:00:00Z"
}Properties:
invitation_id: Unique identifier of the invitationtoken: The invitation token. Returned only at creation — subsequent reads showtoken_prefixinstead. The client application is responsible for building the authorize URL with theinvitation_tokenparameter.audience: Audience identifier the invitation is bound tostatus: Invitation status (pending)claims: Pre-assigned custom claims, ornullif nonenote: Admin note, ornullif nonecreated_at: ISO 8601 timestamp (UTC) when the invitation was createdexpires_at: ISO 8601 timestamp (UTC) when the invitation expires
Use Cases:
- Invite specific people to register for a closed-registration audience
- Pre-assign roles or department claims during onboarding
- Create time-limited invitations for contractors or temporary team members
List Invitations
Path: /api/v1/admin/invitations
Method: GET
Authentication: Bearer token with admin:invitations:read scope
Purpose: Retrieves a paginated list of all invitations across all audiences and creators.
Query Parameters:
page(optional): Zero-indexed page number (default:0)size(optional): Number of results per page (default:20)status(optional): Filter by invitation status (pending,used,revoked,expired)audience(optional): Filter by audience identifier
Response Format:
{
"invitations": [
{
"invitation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"token_prefix": "dGhpcyBp",
"audience": "default",
"status": "pending",
"claims": {
"custom_department": "Engineering",
"role": "admin"
},
"note": "Onboarding Jane from the Engineering team",
"created_at": "2026-03-28T10:00:00Z",
"expires_at": "2026-04-04T10:00:00Z"
}
],
"page": 0,
"size": 20,
"total": 1
}Properties:
invitations: Array of invitation recordsinvitation_id: Unique identifier of the invitationtoken_prefix: First 8 characters of the token, for identification purposes. The full token is never returned after creation.audience: Audience identifierstatus: Invitation status. Possible values:"pending"|"used"|"revoked"|"expired"claims: Pre-assigned custom claims, ornullnote: Admin note, ornullcreated_at: ISO 8601 timestamp (UTC) when the invitation was createdexpires_at: ISO 8601 timestamp (UTC) when the invitation expires
page: Current page numbersize: Number of results per pagetotal: Total number of invitations matching the filters
Use Cases:
- List all pending invitations in an admin dashboard
- Audit invitation usage across audiences
- Find expired or unused invitations for cleanup
Get Invitation
Path: /api/v1/admin/invitations/{invitation_id}
Method: GET
Authentication: Bearer token with admin:invitations:read scope
Purpose: Retrieves details for a specific invitation. When the invitation has been used, the response includes the user_id and used_at fields.
Path Parameters:
invitation_id: Unique identifier of the invitation
Response Format:
200 OK (pending invitation):
{
"invitation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"token_prefix": "dGhpcyBp",
"audience": "default",
"status": "pending",
"claims": {
"custom_department": "Engineering",
"role": "admin"
},
"note": "Onboarding Jane from the Engineering team",
"created_at": "2026-03-28T10:00:00Z",
"expires_at": "2026-04-04T10:00:00Z"
}200 OK (used invitation):
{
"invitation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"token_prefix": "dGhpcyBp",
"audience": "default",
"status": "used",
"claims": {
"custom_department": "Engineering",
"role": "admin"
},
"note": "Onboarding Jane from the Engineering team",
"created_at": "2026-03-28T10:00:00Z",
"expires_at": "2026-04-04T10:00:00Z",
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"used_at": "2026-03-29T09:15:00Z"
}404 Not Found:
{
"error": "not_found",
"error_description": "No invitation found with id: a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}Properties:
invitation_id: Unique identifier of the invitationtoken_prefix: First 8 characters of the tokenaudience: Audience identifierstatus: Invitation status (pending,used,revoked,expired)claims: Pre-assigned custom claims, ornullnote: Admin note, ornullcreated_at: ISO 8601 timestamp (UTC) when the invitation was createdexpires_at: ISO 8601 timestamp (UTC) when the invitation expiresuser_id: Identifier of the user who redeemed the invitation (only present whenstatusisused)used_at: ISO 8601 timestamp (UTC) when the invitation was redeemed (only present whenstatusisused)
Use Cases:
- Check whether an invitation has been used and by whom
- Verify invitation details before sharing with the intended user
- Audit invitation lifecycle for compliance
Revoke Invitation
Path: /api/v1/admin/invitations/{invitation_id}/revoke
Method: POST
Authentication: Bearer token with admin:invitations:write scope
Purpose: Revokes a pending invitation. The invitation can no longer be redeemed. This operation is immediate and permanent.
Path Parameters:
invitation_id: Unique identifier of the invitation
Response Format:
200 OK:
{
"invitation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "revoked"
}404 Not Found:
{
"error": "not_found",
"error_description": "No invitation found with id: a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}Use Cases:
- Revoke an invitation that was sent to the wrong person
- Cancel an invitation after an employee's offer is rescinded
- Clean up unused invitations as part of a security audit