Skip to content

API Reference: SCIM Provisioning

Base path: /api/scim/v2

Arbitex implements SCIM 2.0 (RFC 7643/7644) for automated user and group lifecycle management. Identity providers (Okta, Azure Active Directory, JumpCloud, etc.) can provision, update, and deprovision users and groups automatically.

Authentication: All SCIM endpoints use a long-lived SCIM bearer token (not a user session token). Generate this token from the admin console or via the provisioning API.


POST /api/admin/scim/token
Authorization: Bearer <admin-token>
Content-Type: application/json
{
"description": "Okta SCIM provisioner",
"expires_at": null
}

Response 201 Created:

{
"token_id": "scim_tok_01HXYZ",
"token": "scim_01HXYZ...",
"description": "Okta SCIM provisioner",
"created_at": "2026-03-12T10:00:00Z",
"expires_at": null,
"note": "Store this token securely — it will not be shown again."
}
GET /api/admin/scim/tokens
Authorization: Bearer <admin-token>
{
"tokens": [
{
"token_id": "scim_tok_01HXYZ",
"description": "Okta SCIM provisioner",
"created_at": "2026-03-12T10:00:00Z",
"last_used_at": "2026-03-12T14:00:00Z",
"expires_at": null
}
]
}
DELETE /api/admin/scim/tokens/{token_id}
Authorization: Bearer <admin-token>

Response 204 No Content.


GET /api/scim/v2/ServiceProviderConfig
Authorization: Bearer <scim-token>

Response:

{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig"],
"documentationUri": "https://docs.arbitex.io/reference/api-scim",
"patch": {"supported": true},
"bulk": {"supported": false, "maxOperations": 0, "maxPayloadSize": 0},
"filter": {"supported": true, "maxResults": 200},
"changePassword": {"supported": false},
"sort": {"supported": false},
"etag": {"supported": false},
"authenticationSchemes": [
{
"name": "OAuth Bearer Token",
"description": "Authentication scheme using OAuth Bearer Token",
"type": "oauthbearertoken",
"primary": true
}
],
"meta": {
"resourceType": "ServiceProviderConfig",
"location": "https://api.arbitex.example.com/api/scim/v2/ServiceProviderConfig"
}
}

GET /api/scim/v2/Users
Authorization: Bearer <scim-token>

Query parameters:

ParameterTypeDescription
filterstringSCIM filter expression, e.g. userName eq "alice@acme.com"
startIndexinteger1-based pagination start (default: 1)
countintegerMax results per page (default: 100, max: 200)

Supported filter attributes: userName, emails, active, externalId

Response:

{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"totalResults": 250,
"startIndex": 1,
"itemsPerPage": 100,
"Resources": [
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"id": "usr_01HXYZ",
"externalId": "okta_00u1...",
"userName": "alice@acme.com",
"name": {
"formatted": "Alice Smith",
"familyName": "Smith",
"givenName": "Alice"
},
"emails": [{"value": "alice@acme.com", "primary": true}],
"active": true,
"groups": [
{"value": "grp_01HXYZ", "display": "Engineering"}
],
"meta": {
"resourceType": "User",
"created": "2026-01-15T10:00:00Z",
"lastModified": "2026-03-01T09:00:00Z",
"location": "https://api.arbitex.example.com/api/scim/v2/Users/usr_01HXYZ"
}
}
]
}
GET /api/scim/v2/Users/{id}
Authorization: Bearer <scim-token>

Returns a single User resource. 404 if not found.

POST /api/scim/v2/Users
Authorization: Bearer <scim-token>
Content-Type: application/scim+json
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"externalId": "okta_00u1...",
"userName": "bob@acme.com",
"name": {
"familyName": "Jones",
"givenName": "Bob"
},
"emails": [{"value": "bob@acme.com", "primary": true}],
"active": true
}

Response 201 Created: Full User resource with generated id.

If userName already exists, returns 409 Conflict:

{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"status": "409",
"detail": "User with userName 'bob@acme.com' already exists.",
"scimType": "uniqueness"
}
PUT /api/scim/v2/Users/{id}
Authorization: Bearer <scim-token>
Content-Type: application/scim+json
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"id": "usr_01HXYZ",
"externalId": "okta_00u1...",
"userName": "alice@acme.com",
"name": {"familyName": "Smith", "givenName": "Alice"},
"emails": [{"value": "alice@acme.com", "primary": true}],
"active": true
}

Response 200 OK: Updated User resource.

PATCH /api/scim/v2/Users/{id}
Authorization: Bearer <scim-token>
Content-Type: application/scim+json
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{"op": "replace", "path": "active", "value": false},
{"op": "replace", "path": "name.givenName", "value": "Alicia"}
]
}

Supported op values: add, replace, remove

Deprovisioning a user (set active: false):

{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{"op": "replace", "path": "active", "value": false}
]
}

Deprovisioned users have their sessions revoked and API keys suspended. The user record is retained for audit purposes.

DELETE /api/scim/v2/Users/{id}
Authorization: Bearer <scim-token>

Response 204 No Content.

Hard-deletes the user. Sessions and API keys are immediately revoked. Audit log entries are anonymized per retention policy. This is irreversible — prefer active: false PATCH for soft deprovisioning.


GET /api/scim/v2/Groups
Authorization: Bearer <scim-token>

Query parameters: filter, startIndex, count (same as Users)

Supported filter attributes: displayName, externalId

Response:

{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"totalResults": 12,
"startIndex": 1,
"itemsPerPage": 100,
"Resources": [
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"id": "grp_01HXYZ",
"externalId": "okta_00g1...",
"displayName": "Engineering",
"members": [
{"value": "usr_01HXYZ", "display": "Alice Smith"},
{"value": "usr_02HXYZ", "display": "Bob Jones"}
],
"meta": {
"resourceType": "Group",
"created": "2026-01-15T10:00:00Z",
"lastModified": "2026-03-01T09:00:00Z",
"location": "https://api.arbitex.example.com/api/scim/v2/Groups/grp_01HXYZ"
}
}
]
}
GET /api/scim/v2/Groups/{id}
Authorization: Bearer <scim-token>
POST /api/scim/v2/Groups
Authorization: Bearer <scim-token>
Content-Type: application/scim+json
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"externalId": "okta_00g1...",
"displayName": "Data Science",
"members": [
{"value": "usr_01HXYZ"}
]
}

Response 201 Created: Full Group resource.

Update Group (PATCH — Add/Remove Members)

Section titled “Update Group (PATCH — Add/Remove Members)”
PATCH /api/scim/v2/Groups/{id}
Authorization: Bearer <scim-token>
Content-Type: application/scim+json
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{
"op": "add",
"path": "members",
"value": [{"value": "usr_03HXYZ"}]
},
{
"op": "remove",
"path": "members[value eq \"usr_01HXYZ\"]"
}
]
}
DELETE /api/scim/v2/Groups/{id}
Authorization: Bearer <scim-token>

Response 204 No Content.

Group members are not deleted — only the group is removed. DLP overrides and model access rules tied to the group are also removed.


In Okta:

  1. Application → Provisioning → Integration → API Authentication

    • SCIM connector base URL: https://api.arbitex.example.com/api/scim/v2
    • Authentication mode: HTTP Header
    • Authorization: Bearer <scim-token>
  2. Enable provisioning features:

    • Push New Users: ✓
    • Push Profile Updates: ✓
    • Push Groups: ✓
    • Deactivate Users: ✓ (sets active: false)
  3. Attribute mapping (Okta → SCIM):

    Okta AttributeSCIM Attribute
    loginuserName
    firstNamename.givenName
    lastNamename.familyName
    emailemails[primary eq true].value
    appuser.externalIdexternalId
  1. Enterprise Application → Provisioning → Automatic

    • Tenant URL: https://api.arbitex.example.com/api/scim/v2
    • Secret Token: <scim-token>
  2. Attribute mapping → User:

    • userPrincipalNameuserName
    • mailemails[type eq "work"].value
    • displayNamename.formatted
  3. Scope: Assign to all users or specific groups as needed.


StatusSCIM Error TypeDescription
400invalidFilterUnsupported filter syntax
400invalidValueField value failed validation
401Missing or invalid SCIM token
403Operation not permitted
404Resource not found
409uniquenessUsername or externalId conflict

All errors follow the SCIM error schema:

{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"status": "400",
"scimType": "invalidFilter",
"detail": "Filter attribute 'nickname' is not supported."
}