SCIM Provisioning Admin Guide
import { Aside, Steps, Tabs, TabItem } from ‘@astrojs/starlight/components’;
SCIM Provisioning Admin Guide
Section titled “SCIM Provisioning Admin Guide”SCIM 2.0 (System for Cross-domain Identity Management) automates user and group lifecycle management between your identity provider and Arbitex. This guide walks administrators through end-to-end setup for Okta and Microsoft Entra ID, explains attribute mapping configuration, and documents known limitations.
For the full SCIM API endpoint reference, see SCIM 2.0 Provisioning.
Overview
Section titled “Overview”When SCIM is configured, your IdP becomes the authoritative source for user accounts and groups:
- Automated provisioning — Users assigned to the Arbitex app in your IdP are automatically created in Arbitex
- Real-time deprovisioning — Removing a user from the IdP immediately deactivates their Arbitex access
- Group sync — IdP groups map to Arbitex groups, which drive policy rule enforcement
- Attribute sync — Email, display name, and group membership stay in sync automatically
SCIM works alongside SSO (SAML or OIDC). SCIM provisions the account; SSO handles authentication. Both should be configured.
How group sync drives policy enforcement
Section titled “How group sync drives policy enforcement”The Policy Engine evaluates user.groups conditions against the groups synced via SCIM:
User is member of "financial-analysts" in Okta→ Okta syncs group to Arbitex via SCIM→ Policy rule: IF user.groups contains "financial-analysts" → allow model gpt-4o→ User gets access on next loginGroup membership changes propagate on the IdP’s next sync cycle (Okta: up to 5 minutes; Entra ID: 40-minute incremental cycle, or on-demand sync).
Prerequisites
Section titled “Prerequisites”Before configuring SCIM:
- You have admin access to your Arbitex organization
- SSO (SAML or OIDC) is configured and working — see SSO Configuration
- You have an Arbitex admin API key (found in Admin → API Keys)
- You have IdP admin permissions to create apps and configure provisioning
Step 1: Generate a SCIM token
Section titled “Step 1: Generate a SCIM token”The SCIM token is a bearer secret that your IdP uses to authenticate to the Arbitex SCIM endpoint. Generate it using the admin API:
curl -X POST "https://api.arbitex.ai/v1/orgs/{org_id}/scim/token/rotate" \ -H "Authorization: Bearer $ARBITEX_ADMIN_API_KEY" \ -H "Content-Type: application/json"Response:
{ "token": "scim_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "org_id": "8d4b2c1e-0a3f-4e9d-b7c6-1a2b3c4d5e6f", "created_at": "2026-03-12T00:00:00Z"}Save the token securely in your password manager. You will enter it in your IdP in the next steps.
SCIM base URL: https://api.arbitex.ai/scim/v2
Step 2: Configure your IdP
Section titled “Step 2: Configure your IdP”Okta Setup Wizard
Section titled “Okta Setup Wizard”Arbitex is not in the Okta Integration Network (OIN) gallery as a pre-built app. Use the generic SCIM 2.0 (custom) app type instead.
-
Create a new app integration
In the Okta Admin Console, navigate to Applications → Applications → Create App Integration.
Select:
- Sign-in method: SAML 2.0 (or OIDC if you configured OIDC SSO for Arbitex)
- App type: Web Application
If you already have an Okta SSO app for Arbitex, you can add SCIM provisioning to the existing app (skip to step 3).
-
Enable SCIM provisioning on the app
In the Okta app settings, go to the General tab and find Provisioning. Click Edit and set the provisioning type to SCIM 2.0.
If the Provisioning tab is not visible, go to General → App Settings → Edit and enable Enable SCIM provisioning.
-
Configure SCIM connection settings
Navigate to Provisioning → Integration.
Field Value SCIM connector base URL https://api.arbitex.ai/scim/v2Unique identifier field for users userNameSupported provisioning actions Check: Push New Users, Push Profile Updates, Push Groups, Import New Users and Profile Updates, Import Groups Authentication Mode HTTP Header Authorization Bearer <your-scim-token>Click Test Connector Configuration. Okta will perform a
GET /scim/v2/Users?count=1request. A successful response confirms connectivity. -
Configure attribute mappings (To App)
Navigate to Provisioning → To App → Attribute Mappings.
Set the following mappings:
Okta Attribute SCIM Attribute Mapping Type appuser.emailuserNameExpression appuser.emailemails[type eq "work"].valueExpression appuser.displayNamedisplayNameDirect appuser.firstNamename.givenNameDirect appuser.lastNamename.familyNameDirect appuser.loginexternalIdExpression Expression for userName and email:
appuser.emailExpression for externalId (uses the Okta user ID for stable correlation):
appuser.getInternalProperty("id") -
Configure Group Push
Navigate to Push Groups.
Click Push Groups → Find groups by name and add each Okta group you want to sync to Arbitex. Alternatively, click Find groups by rule and create a rule to push all groups matching a naming convention (e.g.,
arbitex-*).Enable Push group memberships immediately if you want real-time group sync (instead of waiting for the scheduled sync cycle).
-
Assign users to the app
Navigate to Assignments. Assign either individual users or the groups whose members should be provisioned.
Only users (or members of groups) assigned to the Arbitex app will be provisioned. Assigning a group automatically provisions all current members and future additions.
-
Trigger initial sync
Navigate to Provisioning → Import. Click Import Now to perform an initial import that creates Arbitex accounts for all assigned users.
Monitor the Tasks view for any provisioning errors. Common errors on first sync:
- 409 Conflict — A user with that email was already created manually in Arbitex
- 400 Bad Request — Attribute mapping is missing a required field (usually
userName)
Okta sync timing
Section titled “Okta sync timing”| Event | Sync behavior |
|---|---|
| User assigned to app | Provisioned within 1–2 minutes |
| User removed from app | Deprovisioned within 1–2 minutes |
| Group membership change | Synced on next scheduled cycle (up to 5 minutes) or on Group Push trigger |
| Profile update (email, name) | Synced within 5 minutes if “Push Profile Updates” is enabled |
Microsoft Entra ID Setup
Section titled “Microsoft Entra ID Setup”Arbitex is available in the Microsoft Entra ID enterprise app gallery as Arbitex AI Gateway. You can also configure manually using the generic SCIM 2.0 app template.
-
Add the enterprise application
In the Azure Portal, navigate to Microsoft Entra ID → Enterprise Applications → New Application.
Search for Arbitex AI Gateway and select it, or choose Create your own application → Integrate any other application you don’t find in the gallery (Non-gallery).
Name the application (e.g., “Arbitex AI Gateway”) and click Create.
-
Configure single sign-on (if not already done)
Before configuring provisioning, ensure SSO is set up for the same application. SCIM requires users to be assigned to the app, and assignment is managed in one place.
See SSO Configuration for the SAML setup steps.
-
Configure automatic provisioning
Navigate to the application → Provisioning → Get started.
Setting Value Provisioning Mode Automatic Tenant URL https://api.arbitex.ai/scim/v2Secret Token <your-scim-token>(without theBearerprefix)Click Test Connection. Entra ID performs a
GET /scim/v2/Users?count=1to validate the connection. A success message confirms connectivity. -
Configure attribute mappings
Navigate to Mappings → Provision Microsoft Entra ID Users.
Verify or configure the following attribute mappings:
Entra ID Attribute SCIM Attribute Matching Precedence userPrincipalNameuserNamePrimary (1) mailemails[type eq "work"].value— displayNamedisplayName— givenNamename.givenName— surnamename.familyName— objectIdexternalId— IsSoftDeletedactive— (inverted: false→ activefalse)Navigate to Mappings → Provision Microsoft Entra ID Groups.
Verify or configure:
Entra ID Attribute SCIM Attribute displayNamedisplayNameobjectIdexternalIdmembersmembers -
Set provisioning scope
Navigate to Settings.
Setting Recommended value Scope Sync only assigned users and groups Notification Email Your IT admin email (receives provisioning error alerts) Send an email notification when a failure occurs Enabled Setting scope to “Sync only assigned users and groups” ensures only users explicitly assigned to the app are provisioned. Using “Sync all users and groups” provisions your entire directory.
-
Assign users and groups
Navigate to Users and groups → Add user/group.
Assign the groups (not individual users) that should be provisioned to Arbitex. All members of assigned groups will be provisioned.
Assign the Arbitex Admins group if you have one — admin users need to be provisioned before they can access the admin panel.
-
Start provisioning
Navigate to Provisioning → Overview. Toggle provisioning to On.
Click Provision on demand to provision a specific user immediately (useful for testing). Enter a user’s UPN, click Provision, and verify the result in the audit log.
Entra will begin the initial sync cycle. Initial full sync can take 20–40 minutes for large directories.
-
Monitor provisioning
Navigate to Provisioning → Provisioning logs to see individual provisioning events.
Filter by Status: Failure to identify any errors. Common errors:
- InvalidLicense — The user exists in Arbitex but their account type doesn’t support SCIM-managed attributes
- DuplicateTargetEntries — Duplicate email in Arbitex; resolve the conflict manually
Entra ID sync timing
Section titled “Entra ID sync timing”| Event | Sync behavior |
|---|---|
| Initial provisioning | 20–40 minutes |
| Incremental sync | Every 40 minutes (automatic) |
| On-demand sync | Immediate (via “Provision on demand” or Graph API) |
| Group membership change | Included in next incremental sync cycle |
| User deprovisioning | Included in next incremental sync (or on-demand) |
Attribute Mapping Reference
Section titled “Attribute Mapping Reference”User attribute mappings
Section titled “User attribute mappings”| SCIM Attribute | Arbitex Field | Required | Notes |
|---|---|---|---|
userName | email + username | Yes | Used as primary identifier. Must be unique email. |
emails[primary].value | email | No | Used if userName is not an email format |
displayName | display_name | No | Shown in admin UI and audit logs |
name.givenName | first_name | No | Stored but not required |
name.familyName | last_name | No | Stored but not required |
externalId | external_id | No | IdP-side identifier for deduplication; strongly recommended |
active | is_active | No | false deactivates the account and revokes all active sessions |
Recommendation: Always map externalId to the IdP’s stable user object ID (Okta: getInternalProperty("id"), Entra: objectId). This prevents duplicate account creation if a user’s email changes.
Group attribute mappings
Section titled “Group attribute mappings”| SCIM Attribute | Arbitex Field | Notes |
|---|---|---|
displayName | name | Group name — used in policy rule user.groups conditions |
externalId | external_group_id | IdP group object ID; used for SSO claim mapping |
members[].value | Group membership | Arbitex user UUIDs (not IdP UUIDs) |
Arbitex group extension attributes
Section titled “Arbitex group extension attributes”The urn:arbitex:scim:schemas:extension:Group:2.0 extension allows group-level policy configuration from the IdP:
| Extension Attribute | Type | Description |
|---|---|---|
dlpPolicy | string | Override DLP action: SKIP / BLOCK / CANCEL / REDACT |
modelAccess | string array | Permitted model IDs for group members |
complianceBundles | string array | Compliance bundle IDs active for this group |
quotaTokens | integer | Daily token quota for group members |
Example group with extension attributes:
{ "schemas": [ "urn:ietf:params:scim:schemas:core:2.0:Group", "urn:arbitex:scim:schemas:extension:Group:2.0" ], "displayName": "data-science-team", "externalId": "grp_ds_001", "members": [ { "value": "user-uuid-alice" }, { "value": "user-uuid-bob" } ], "urn:arbitex:scim:schemas:extension:Group:2.0": { "modelAccess": ["gpt-4o", "claude-3-5-sonnet"], "quotaTokens": 500000, "complianceBundles": ["soc2-type2"] }}Known Gaps and Limitations
Section titled “Known Gaps and Limitations”The following are known limitations of the current SCIM implementation:
Unsupported SCIM features
Section titled “Unsupported SCIM features”| Feature | Status | Workaround |
|---|---|---|
PATCH /Users — nested path operations | Not supported | Use PUT /Users/{id} for full user replacement |
Complex filter expressions (and, or, not) | Not supported | Filters are limited to single-attribute equality; IdP handles complex filtering client-side |
Bulk operations (/scim/v2/Bulk) | Not supported | Operations are performed individually |
SCIM /Me endpoint | Not supported | — |
Sorting (sortBy, sortOrder) | Not supported | Results are returned in insertion order |
schema discovery via /scim/v2/ResourceTypes | Partially supported | Returns Users and Groups only; extension schema not in ServiceProviderConfig |
Provisioning behavior gaps
Section titled “Provisioning behavior gaps”| Behavior | Current | Impact |
|---|---|---|
| Group delete propagation | Group DELETE removes the group but does not automatically remove users from the group policy context | Users retain group-derived permissions until policy is re-evaluated on next request |
| Concurrent PATCH operations | Not atomic | Rapid sequential PATCH operations from the IdP (e.g., bulk member adds during initial sync) may result in eventual consistency rather than guaranteed ordering |
| User restore after soft-delete | PATCH active: true re-activates; historical audit logs are preserved but conversation history access must be re-granted manually | — |
| Multi-value email attributes | Only primary: true email is used; secondary emails are ignored | — |
| Display name as username | displayName is mapped to username (display field); userName (email) is the primary login identifier | Some IdP configurations set displayName to a non-email value — ensure userName is always the email |
Entra ID-specific gaps
Section titled “Entra ID-specific gaps”| Issue | Detail |
|---|---|
| Nested group membership | Entra ID SCIM provisioning flattens nested groups — members of nested groups are NOT automatically provisioned. Assign all groups (including parent and child) directly to the app. |
| Group member limit | Entra ID SCIM provisioning has a 1500-member limit per group in a single sync operation. Larger groups may require multiple sync cycles or manual member provisioning. |
| Provisioning scope change | Changing scope from “Sync assigned users and groups” to “Sync all” triggers a full re-sync which may take several hours for large directories. |
Okta-specific gaps
Section titled “Okta-specific gaps”| Issue | Detail |
|---|---|
| Okta Push Groups vs Import Groups | Push Groups is used to push Okta groups TO Arbitex; Import Groups imports Arbitex groups INTO Okta. For most setups, only Push Groups is needed. Enabling both can create sync loops if not configured carefully. |
| Profile mastering | If Okta is set as the profile master for the Arbitex app, Okta will override any manual attribute changes made in Arbitex. This is the intended behavior for SCIM. |
| App deactivation behavior | When the Arbitex app is deactivated in Okta (vs. a user being unassigned), Okta sends PATCH active: false for all provisioned users. This deactivates all users simultaneously. |
Troubleshooting
Section titled “Troubleshooting”401 Unauthorized — Token rejected
Section titled “401 Unauthorized — Token rejected”Symptom: All SCIM operations return 401.
Causes and resolutions:
-
Token was rotated — Check if the SCIM token was recently rotated. Run:
Terminal window curl -X POST "https://api.arbitex.ai/v1/orgs/{org_id}/scim/token/rotate" \-H "Authorization: Bearer $ARBITEX_ADMIN_API_KEY"Update your IdP with the new token immediately.
-
Incorrect Authorization header — Some IdPs include or omit the
Bearerprefix incorrectly.- Okta: Enter the raw token in the “Authorization” field; Okta prepends
Bearerautomatically - Entra ID: Enter the raw token (without
Bearer) in the “Secret Token” field
- Okta: Enter the raw token in the “Authorization” field; Okta prepends
-
Org ID mismatch — Verify the SCIM token was generated for the correct org ID.
403 Forbidden — SCIM not configured
Section titled “403 Forbidden — SCIM not configured”Symptom: First-time setup returns 403.
Cause: No SCIM token has been generated for the org.
Resolution: Run POST /v1/orgs/{org_id}/scim/token/rotate to create the initial token.
409 Conflict — Duplicate user
Section titled “409 Conflict — Duplicate user”Symptom: User provisioning fails with 409 Conflict.
Cause: A user with the same userName (email) already exists in Arbitex, created before SCIM was configured.
Resolution options:
-
Link existing user to SCIM (recommended) — Update the existing user’s
externalIdto match the IdP’s user object ID:Terminal window curl -X PATCH "https://api.arbitex.ai/scim/v2/Users/{arbitex_user_id}" \-H "Authorization: Bearer $SCIM_TOKEN" \-H "Content-Type: application/json" \-d '{"schemas":["urn:ietf:params:scim:api:messages:2.0:PatchOp"],"Operations":[{"op":"replace","path":"externalId","value":"idp-user-object-id"}]}'After linking, the IdP will find the existing user by
externalIdoruserNameand update rather than create. -
Delete and re-create — Delete the manually created user from Arbitex admin panel, then trigger a re-sync from the IdP.
Group members not appearing in Arbitex
Section titled “Group members not appearing in Arbitex”Symptom: Groups are synced but some members are missing.
Checklist:
- Are the missing users assigned to the Arbitex app? (Okta: check Assignments; Entra: check Users and groups)
- Did the user provisioning succeed before the group PATCH was sent? Group PATCH uses Arbitex user UUIDs — if the user doesn’t exist yet, the member is silently skipped
- For Entra ID: check for the 1500-member limit issue — look for “SkippedMember” entries in provisioning logs
- Check the IdP provisioning log for group operations — look for PATCH operations with
memberspath
Users deprovisioned but still able to log in
Section titled “Users deprovisioned but still able to log in”Symptom: User’s is_active is false but they can still start new sessions.
Cause: Active sessions (JWT tokens) are not invalidated immediately when the user is deactivated via SCIM. Active sessions remain valid until they expire.
Resolution: To immediately invalidate all active sessions for a deactivated user:
# Force-invalidate all sessions for a user (admin API)curl -X POST "https://api.arbitex.ai/api/admin/users/{user_id}/invalidate-sessions" \ -H "Authorization: Bearer $ARBITEX_ADMIN_API_KEY"Session max lifetime is configurable in Admin → Organization → Session Policy. Default is 8 hours.
Initial sync takes too long
Section titled “Initial sync takes too long”Symptom: Full sync has been running for hours with no errors but not all users are provisioned.
Recommendations:
- For Entra ID: large directories (>10,000 users) can take 2–4 hours for initial full sync. This is normal; incremental syncs will be faster.
- For Okta: check the “Tasks” view for any paused or failed operations
- Verify rate limiting is not a factor — Arbitex enforces a per-org SCIM rate limit of 100 requests/second. Large syncs approaching this limit will be throttled (HTTP 429 responses)
SCIM rate limit hit (HTTP 429)
Section titled “SCIM rate limit hit (HTTP 429)”Symptom: Some provisioning operations return 429.
Cause: The IdP is sending too many requests per second during bulk sync.
Response headers on 429:
Retry-After: 60X-RateLimit-Limit: 100X-RateLimit-Remaining: 0X-RateLimit-Reset: 1710000000Resolution: Most IdPs automatically honor Retry-After. If your IdP does not, configure a rate limit or throttle setting in its provisioning connector. For Entra ID, this is handled automatically. For Okta, throttling is automatic.
Verifying SCIM setup
Section titled “Verifying SCIM setup”After completing setup, verify provisioning is working:
# 1. Verify the SCIM endpoint is reachable and authenticatedcurl "https://api.arbitex.ai/scim/v2/ServiceProviderConfig" \ -H "Authorization: Bearer $SCIM_TOKEN"
# 2. List provisioned userscurl "https://api.arbitex.ai/scim/v2/Users?count=5" \ -H "Authorization: Bearer $SCIM_TOKEN"
# 3. List provisioned groupscurl "https://api.arbitex.ai/scim/v2/Groups?count=5" \ -H "Authorization: Bearer $SCIM_TOKEN"
# 4. Verify a specific user was provisioned with correct attributescurl "https://api.arbitex.ai/scim/v2/Users?filter=userName eq \"alice@example.com\"" \ -H "Authorization: Bearer $SCIM_TOKEN"Expected output for step 4:
{ "schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"], "totalResults": 1, "Resources": [{ "id": "user-uuid-here", "userName": "alice@example.com", "displayName": "Alice Smith", "active": true, "externalId": "okta-user-object-id", "meta": { "resourceType": "User", "created": "2026-03-12T00:00:00Z", "lastModified": "2026-03-12T00:00:00Z" } }]}Rotating the SCIM token
Section titled “Rotating the SCIM token”SCIM tokens do not expire automatically. Rotate them on your security rotation schedule (recommended: every 90 days, or immediately after personnel changes).
-
Generate a new token (previous token remains active until step 3):
Terminal window curl -X POST "https://api.arbitex.ai/v1/orgs/{org_id}/scim/token/rotate" \-H "Authorization: Bearer $ARBITEX_ADMIN_API_KEY"Copy the new raw token immediately.
-
Update your IdP with the new token:
- Okta: Provisioning → Integration → Edit → update Authorization field → Save → Test Connector Configuration
- Entra ID: Provisioning → Edit provisioning → update Secret Token → Test Connection → Save
-
Verify the new token works by triggering an on-demand sync of one user.
-
Invalidation note: Token rotation immediately invalidates the previous token. If you have multiple IdPs (e.g., Okta AND Entra ID) both using SCIM, note that Arbitex only supports one active SCIM token per org. Both IdPs must be updated simultaneously.
See also
Section titled “See also”- SCIM 2.0 API Reference — Full endpoint reference with request/response examples
- SSO Configuration — SAML and OIDC configuration for Okta and Entra ID
- User & Group Management — Manual user and group management
- Entra ID SCIM Guide — Entra ID gallery app detailed setup
- MFA Enforcement — Require MFA for SCIM-provisioned users