Enterprise
Directory sync (SCIM)
Provision and deactivate members from Okta, Entra ID or any SCIM 2.0 client, with groups mapped to roles.
SCIM 2.0 lets Okta, Microsoft Entra ID or any RFC 7644 client create, update and deactivate the members of one workspace, and choose their roles through group membership. It is an Enterprise feature, configured by a workspace owner in Settings → Directory sync or with crit scim.
SCIM is built into web; there is no extra service and no environment variable to set.
Set up
- In Settings → Directory sync, create a token (
crit scim token create <name>). It starts withcrit_scim_and is shown once; critlab stores only a hash. - In your IdP's SCIM app, enter:
| IdP field | Value |
|---|---|
| SCIM base URL | https://critlab.example.com/scim/v2 |
| Authentication | HTTP header / OAuth bearer token |
| Token | the crit_scim_… token |
- Map attributes (below), assign people and push groups.
To rotate a token, create a second one, switch the IdP to it, then revoke the first. Revoking stops provisioning immediately and changes no members.
The SCIM endpoints accept the bearer token only, never a browser session, and allow 60 requests per minute per token.
Attribute mapping
| SCIM attribute | critlab | Notes |
|---|---|---|
userName | Must be an email address; anything else is refused with invalidValue. | |
emails[type eq "work"].value | Primary, then work, then the first address. | |
name.givenName, name.familyName | Display name | Stored as one name. |
externalId | External id | Keeps a person matched across an email change. |
active | Membership active | false deactivates (below). |
Roles are read-only over SCIM: a directory sets a role through groups.
Groups and roles
Pushed groups arrive with no role, so naming a group critlab-admins grants nothing by itself. A group's role comes from, in order:
- the mapping an owner sets in Settings → Directory sync (
crit scim map <group> <role>), - otherwise an entry of the same name in the workspace's SAML role map, so a workspace that already configured SSO gets working roles with no extra setup,
- otherwise nothing.
A member's role is the strongest role any of their groups grants, else the workspace's default role, else member. It is recomputed on every membership change, in both directions: leaving an admin group removes admin.
Two rules the directory cannot override:
- SCIM never grants owner. Group-derived roles are capped at admin. Ownership is granted by a person in critlab.
- SCIM never changes or deactivates an owner. The directory gets a success response (so it does not retry forever) and the skipped change is logged as
scim.role_sync_skipped.
Groups can map to guest, but SCIM never grants folder access: a directory-provisioned guest sees an empty workspace until an owner or admin grants folders. See Roles and guest access.
Deactivation
active: false, or DELETE /Users/{id}, deactivates the membership rather than deleting it:
- the person loses access to the workspace immediately and stops counting as a seat;
- all of their sessions are revoked, including in other workspaces, because deactivation is what happens when someone leaves;
- their comments, and their account, stay;
- reactivating restores their role and groups.
Signing in
A provisioned person has no password and signs in through the workspace's SAML connection (configure Single sign-on first). Configure the IdP to send the email address as the SAML Name ID, which is the default in Okta and Entra ID SAML apps.
Supported operations
| Method | Path |
|---|---|
GET | /scim/v2/ServiceProviderConfig, /scim/v2/ResourceTypes, /scim/v2/Schemas |
GET, POST | /scim/v2/Users (filter: one eq on userName, externalId, emails.value, id or active; startIndex, count) |
GET, PUT, PATCH, DELETE | /scim/v2/Users/{id} |
GET, POST | /scim/v2/Groups |
GET, PUT, PATCH, DELETE | /scim/v2/Groups/{id} |
Bulk operations, sorting, ETags and compound filters (and/or) are not supported and are declared as such in ServiceProviderConfig; an unsupported filter is refused, never answered approximately. Errors use the SCIM error envelope.
To check a token by hand:
curl -s -H "Authorization: Bearer $SCIM_TOKEN" \
--get "https://critlab.example.com/scim/v2/Users" \
--data-urlencode 'filter=userName eq "ana@acme.com"'Audit trail
Every change is recorded with the actor shown as the SCIM token, so directory changes are easy to tell from people's: scim.user_created, scim.user_updated, scim.user_deactivated, scim.user_reactivated, scim.role_synced, scim.role_sync_skipped, scim.group_created, scim.group_updated, scim.group_deleted, scim.group_members_changed, scim.token_created, scim.token_revoked.