SCIM through Entra
This guide covers the core SCIM setup: enabling SCIM in Stack AI, creating the Entra enterprise app, configuring attribute mappings for users, assigning users, and verifying that provisioning works.
Prerequisites
Stack AI organization admin access
Microsoft Entra tenant with privileges to create Enterprise applications and edit App Registrations
A modern browser tab open to each side
Step 1 — Enable SCIM in Stack AI
Sign in to Stack AI as an org admin.
Open Settings → SCIM Provisioning.
Click Enable SCIM and confirm. This creates a
scim_provisioning_configsrow for your org and unlocks the SCIM endpoints.From the Overview card, copy two values — you'll need them on the Entra side:
Base URL — looks like
https://api.stack-ai.com/scim/v2SCIM token — click Generate token, give it a name (e.g. "Entra Production"), and copy the token immediately. You only see it once; if you lose it, regenerate.
Leave this page open — you'll come back to verify provisioned users.
Step 2 — Create the Enterprise application in Entra
Open the Microsoft Entra admin center.
Identity → Applications → Enterprise applications → + New application.
Click + Create your own application.
Name it (e.g.
Stack AI).Choose "Integrate any other application you don't find in the gallery (Non-gallery)" → Create.
Entra will build the app from its generic SCIM template — that's why provisioning logs and job names will reference customappsso. It's cosmetic and expected.
Step 3 — Configure SCIM credentials and test the connection
In the new app, open the Provisioning blade → Get started.
Set Provisioning Mode = Automatic.
Expand Admin Credentials:
Tenant URL: paste the Stack AI Base URL from Step 1 (
https://api.stack-ai.com/scim/v2)Secret Token: paste the SCIM token from Step 1
Click Test Connection. Entra calls
/ServiceProviderConfigand/Users?count=1. Both should return 200.401: token is wrong or expired — regenerate in Stack AI and re-paste.
404: Tenant URL is wrong — double-check the trailing
/scim/v2.5xx: Stack AI side issue; check Stack AI status before continuing.
Click Save.
Step 4 — Configure user attribute mappings
After saving credentials, the Mappings section appears with two object types: Users and Groups. Start with users — groups are covered in the optional section at the end.
Click Provision Microsoft Entra ID Users.
Enabled: Yes.
Target Object Actions: leave Create / Update / Delete all checked.
Verify (and trim) the attribute mappings. The minimum useful set:
Microsoft Entra attributeTarget SCIM attributeNotesuserPrincipalNameuserNameIdentity key
Switch([IsSoftDeleted], , "False", "True", "True", "False")activeDisables suspended users
objectIdexternalIdStable lookup; survives renames
mailemails[type eq "work"].valueRequired for invites/SSO match
givenNamename.givenNamesurnamename.familyNamedisplayNamedisplayNameYou can delete the rest of Entra's defaults (manager, addresses, phone numbers, etc.) — Stack AI ignores them and removing them reduces sync errors.
Save the mappings.
Step 5 — Assign users to the app
Provisioning scope defaults to "Sync only assigned users and groups". Leave this — broader scopes provision your entire tenant, which you almost never want.
In the same Enterprise application, open the Users and groups blade.
+ Add user/group → pick users (or, later, groups — see the optional group section).
Save.
Only assigned users are eligible for provisioning. Adding more users later is non-destructive — they get picked up on the next sync cycle.
Step 6 — Start provisioning and verify
Back to the Provisioning blade.
Click Start provisioning at the top. Status should switch to Provisioning (green).
To skip the wait, use Provision on demand:
Click Provision on demand
Search for one of the assigned users → Provision
Inspect the result. The "Modify user" or "Create user" step shows the exact SCIM payload sent and the response received.
In Stack AI → Settings → Members, confirm the user appears with the expected name, email, and active state.
Going forward, Entra runs a sync cycle every ~40 minutes. This interval is set by Microsoft and cannot be lowered.
What to expect operationally
Adding a user to the app → next cycle they appear in Stack AI.
Removing a user from the app (or soft-deleting them in Entra) →
active=falseis sent, Stack AI deactivates them. The user record is preserved.Hard-deleting a user in Entra after 30 days → SCIM
DELETE /Users/{id}is sent and the user is removed from Stack AI.Renaming a user → Stack AI updates the existing record, identified via
externalId. No duplicate is created.Quarantine (red banner on the Provisioning blade) → too many failures or auth errors. Fix the underlying issue, then Restart provisioning to clear it.
Troubleshooting checklist
If provisioning isn't behaving:
Provisioning logs (Provisioning blade → "View provisioning logs"). Filter by Status = Failure. Each row shows the request, response, and exact error.
401 Unauthorized on every call → token expired or revoked in Stack AI. Regenerate and update Entra credentials.
403 Forbidden on
/Users→ SCIM was disabled on the Stack AI side. Re-enable from the SCIM Provisioning page.400 invalidValue on
userName→ almost always a missinguserPrincipalNamefor that user. Check the user's profile in Entra.No log rows at all for a user you expected → they're not assigned to the app, or they're in an unassigned group.
Provision on demand is the fastest debug tool. Use it after every config change to validate without waiting for the cycle.
Optional: Group sync
By default, Stack AI mirrors Entra groups one-to-one — same name, same membership. There's no group → role / group → permission translation; the synced group is just a Stack AI group. Skip this section if you only need user provisioning.
Enable group sync in Stack AI
Stack AI → Settings → SCIM Provisioning.
Toggle Sync groups to ON.
If this toggle is off, every Entra /Groups call returns 403 Forbidden and Entra logs will be flooded with group-create failures.
Confirm the Group mapping is enabled in Entra
Provisioning blade → Mappings.
Click Provision Microsoft Entra ID Groups → Enabled = Yes.
Verify the minimum mapping set:
Entra attributeSCIM attributedisplayNamedisplayNameobjectIdexternalIdmembersmembersThe Entra group's
displayNamebecomes the Stack AI group name verbatim. Pick clean, human-readable group names in Entra; they show up directly in Stack AI's UI.
Assign the group to the app
In Users and groups, + Add user/group → pick the group itself (not just its members). Assigning a member's parent group does not implicitly provision the group; the group must be assigned explicitly.
Note: Entra does not expand nested or dynamic groups for SCIM. If you have a group of groups, assign each leaf group separately.
Verify
After the next sync (or via Provision on demand on the group):
The group appears in Stack AI → Settings → Groups.
Members are populated. Adding/removing a user from the Entra group propagates as a SCIM
PATCH(add/remove members) on the next cycle.Renaming the Entra group updates the Stack AI group's name (it's matched by
externalId).Deleting the Entra group removes the Stack AI group; member users are kept.
Optional: Role mapping
By default, provisioned users have no role. To grant roles automatically, you create a translation table in Stack AI ("when Entra sends role X, set Stack AI role Y") and configure Entra to send a role value per user.
How role resolution works
When Stack AI receives a SCIM user payload with a roles array, it:
Picks the role marked
primary: true(or the first if none flagged).Lowercases and trims the value.
Looks for an exact match in your role mappings.
If no match → assigns the configured default role.
If there's no default role → user is provisioned with no role.
Matching is case-insensitive, but whitespace and unicode quirks count. Use plain lowercase tokens (admin, member, viewer).
Step A — Create role mappings in Stack AI
Stack AI → Settings → SCIM Provisioning → Role mappings card.
Set a default role in the SCIM config (highly recommended). This is the safety net for users without a matching role.
+ Add mapping for each label you intend to send from Entra:
IdP role valueStack AI roleadminAdmin
memberMember
viewerViewer
Step B — Define App Roles on the App Registration
App Roles live on the App Registration, not the Enterprise application.
Entra admin → App registrations → open the registration that backs your Stack AI enterprise app (same name).
App roles → + Create app role for each Stack AI role:
Display name: e.g.
Stack AI AdminAllowed member types: Users/Groups
Value:
admin← this is the string sent inroles[].value. Must match theidp_role_valuefrom Step A.Description: anything
Enable this app role?: Yes
Repeat for
member,viewer, etc.
Step C — Assign users (or groups) to App Roles
Back to the Enterprise application → Users and groups.
+ Add user/group → pick a user or group → Select a role → choose the app role → Assign.
Each user can hold one app-role assignment per app. Re-assigning replaces the previous role.
If you assign a group, every member inherits the role for SCIM purposes.
Step D — Map App Roles into the SCIM roles attribute
roles attributeProvisioning blade → Mappings → Provision Microsoft Entra ID Users:
Scroll to the bottom and tick Show advanced options.
Click Edit attribute list for customappsso.
Ensure
rolesexists with Type = String and Multi-Valued = True. Add it if missing. Save.Back in the user mappings list, + Add New Mapping:
Mapping type: Expression
Expression:
SingleAppRoleAssignment([appRoleAssignments])Target attribute:
roles[primary eq "True"].valueMatch objects using this attribute: No
Apply this mapping: Always
Save.
The SingleAppRoleAssignment function emits the user's current app-role Value (e.g. "admin"), placed into roles[0].value with primary=true — exactly what Stack AI's resolver looks for.
Step E — Verify
Provision on demand for a user with an assigned app role.
Inspect the outbound SCIM payload —
rolesshould be present with the right value.In Stack AI → Settings → Members, the user's role should reflect the mapping.
Troubleshooting role mapping
rolesmissing from payload → Step D-3 (schema) wasn't saved, or the user has no app role assigned (Step C).rolespresent but Stack AI uses the default → label mismatch. TheValueon the App Role and theidp_role_valuein Stack AI must match (case-insensitive, no extra whitespace).Existing users not updating → they don't re-resolve until something on their record changes. Either trigger a Provision on demand for each, or wait for the next sync cycle and ensure their app-role assignment was set/changed (which forces an update).
Multiple app-role assignments → not supported by
SingleAppRoleAssignment. Use only one app role per user.
Lightweight alternative
If you don't want to manage App Roles, set a single constant role for everyone:
In Mappings → Provision Microsoft Entra ID Users, + Add New Mapping:
Mapping type: Constant
Constant value:
memberTarget attribute:
roles[primary eq "True"].value
Add one matching role mapping in Stack AI:
member→ Member.
Everyone gets the same role on provisioning; admins are promoted manually inside Stack AI. Simpler, less Entra to manage, but no role differentiation from the IdP.
Quick reference
Who can SSO into Stack AI?
Entra app → Users and groups (assignment), SSO blade (provider config)
Who gets provisioned?
Entra app → Users and groups (must be assigned and in Provisioning scope)
What attributes flow over?
Entra app → Provisioning → Mappings
Where is my SCIM token?
Stack AI → SCIM Provisioning page (regenerate if lost)
Why isn't my group syncing?
(1) Sync groups toggle in Stack AI, (2) group itself assigned to the app, (3) Group mapping enabled in Entra
Why is everyone getting the wrong role?
Role mapping label mismatch, or no roles claim in SCIM payload
How fast does a change propagate?
Every ~40 minutes, or instantly via Provision on demand
Last updated
Was this helpful?

