Skip to main content

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:

  • scim license entitlement (returns 402 without it)
  • SCIM bearer token configured at startup (via SCIM_TOKEN env 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" or displayName eq "Alice Smith"
  • startIndex — 1-based pagination start (default 1)
  • count — page size (default 100)

Response 200SCIMListResponse 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 user
  • password — 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)

  1. In Okta, create an API integration for SCIM
  2. Set the SCIM connector base URL to https://your-deployment/scim/v2
  3. Set the authentication bearer token to your configured SCIM_TOKEN
  4. Enable push for Users and Groups
  5. (Optional) Add X-Tenant-Slug as 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"