SCIM 2.0 Provisioning
Alexandria implements RFC 7644 SCIM 2.0 for automated user and group lifecycle management from identity providers (Okta, Azure AD, etc).
Requirements:
scimlicense entitlement (returns 402 without it)- SCIM bearer token configured at startup (via
SCIM_TOKENenv var or config)
Base path: /scim/v2
Content-Type: application/scim+json
Authentication
SCIM endpoints (except service discovery) require the static SCIM bearer token:
Authorization: Bearer <scim-token>
This is separate from the user JWT. The SCIM token is a high-trust provisioning credential that should not be shared with end users.
Tenant scoping: Pass X-Tenant-Slug: <slug> to scope provisioning to a specific tenant. Falls back to default for single-tenant deployments.
Service discovery (no auth)
Per RFC 7644 §4, service discovery endpoints are unauthenticated.
GET /scim/v2/ServiceProviderConfig
Returns the provider capabilities (filter supported, patch supported, bulk not supported, etc).
GET /scim/v2/Schemas
Returns the User and Group schema definitions.
GET /scim/v2/ResourceTypes
Returns the User and Group resource type definitions.
Users
GET /scim/v2/Users
List users with optional filtering and pagination.
Query params
filter— SCIM filter, e.g.userName eq "alice"ordisplayName eq "Alice Smith"startIndex— 1-based pagination start (default 1)count— page size (default 100)
Response 200 — SCIMListResponse with SCIM user objects.
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"totalResults": 42,
"startIndex": 1,
"itemsPerPage": 10,
"Resources": [
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"id": "01HXZ...",
"userName": "alice",
"displayName": "alice",
"active": true,
"meta": {
"resourceType": "User",
"created": "2026-01-10T09:00:00Z",
"lastModified": "2026-01-10T09:00:00Z",
"location": "/scim/v2/Users/01HXZ..."
}
}
]
}
POST /scim/v2/Users
Provision a new user. If no password is provided, a random placeholder is set — SCIM-provisioned users are expected to authenticate via SSO.
{
"userName": "alice@example.com",
"displayName": "Alice Smith",
"active": true
}
Response 201 — SCIM user object. Response 409 — userName already exists.
GET /scim/v2/Users/{id}
Get user by internal ID.
PUT /scim/v2/Users/{id}
Full replacement. Updates active (enabled/disabled) and optionally password.
PATCH /scim/v2/Users/{id}
Partial update via SCIM operations. Supported paths:
active— enable/disable the userpassword— update password
userName changes are rejected with 400 (not supported after creation).
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{ "op": "replace", "path": "active", "value": false }
]
}
DELETE /scim/v2/Users/{id}
Permanently deletes the user. Returns 204.
Groups
Groups in Alexandria map to AgentGroup objects. Member management via SCIM is acknowledged but member-to-agent assignment is handled via the agent-group relation (outside SCIM scope in this implementation).
GET /scim/v2/Groups
Filter by displayName eq "group-name".
POST /scim/v2/Groups
{
"displayName": "engineering",
"members": []
}
Response 409 — displayName already exists.
GET /scim/v2/Groups/{id}
PUT /scim/v2/Groups/{id}
PATCH /scim/v2/Groups/{id}
Group patch operations are acknowledged. Member management (adding users to groups) requires the agent-group assignment API.
DELETE /scim/v2/Groups/{id}
IdP integration example (Okta)
- In Okta, create an API integration for SCIM
- Set the SCIM connector base URL to
https://your-deployment/scim/v2 - Set the authentication bearer token to your configured
SCIM_TOKEN - Enable push for Users and Groups
- (Optional) Add
X-Tenant-Slugas a custom header to scope to a tenant
# Test connectivity
curl -s "https://your-deployment/scim/v2/ServiceProviderConfig" | jq .
# List users (as IdP would)
curl -s "https://your-deployment/scim/v2/Users?startIndex=1&count=10" \
-H "Authorization: Bearer $SCIM_TOKEN" \
-H "Content-Type: application/scim+json" | jq .
# Provision a user
curl -s -X POST "https://your-deployment/scim/v2/Users" \
-H "Authorization: Bearer $SCIM_TOKEN" \
-H "Content-Type: application/scim+json" \
-d '{"userName":"bob@example.com","active":true}' | jq .
# Deprovision
curl -s -X DELETE "https://your-deployment/scim/v2/Users/$USER_ID" \
-H "Authorization: Bearer $SCIM_TOKEN"