Overview
Vigilo implements SCIM 2.0 (WC.2) for automated user and group lifecycle, including create / read / update / delete on Users and Groups, ETag-based optimistic concurrency via If-Match, startIndex-based pagination, and meta.lastModified timestamps. Combined with SAML or OIDC (covered separately), SCIM lets an IdP like Okta or Azure AD own the entire identity surface — Vigilo never holds an authoritative list of who should be a member, only who currently is.
The SCIM endpoints live under /scim/v2/ and authenticate via a ScimToken, a long-lived bearer token issued from Settings → SCIM → New token. Each workspace runs its own SCIM endpoint with its own token, so an IdP can provision multiple Vigilo workspaces independently.
Why it exists
Manual member management at scale is impossible. A 500-person engineering org might have:
- A new joiner every week who needs the right workspaces with the right roles
- A leaver every two weeks who needs every workspace revoked atomically (failing to do so on a deprovision is a SOX-level audit finding)
- Frequent team moves where roles in some workspaces change
- Custom apps where membership is determined by an IdP group like
eng-prodorcert-operators
SCIM puts the IdP in charge of all of this. The Vigilo admin focuses on policy ("members of the eng-prod group get the approver role in workspace prod") rather than data entry.
Endpoints (SCIM 2.0)
All endpoints accept and return application/scim+json. Standard 2.0 envelopes (schemas, id, meta) apply.
Users
POST /scim/v2/Users/— create a user. Body: SCIM User schema. Returns201with the created user plus anETagheader. Ifemailmatches an existing user, returns409 conflictper spec.GET /scim/v2/Users/?startIndex=1&count=100&filter=userName eq "alice@acme.com"— list with pagination and filter.startIndexis 1-based per SCIM. Filter supportseq,ne,co,sw,pronuserName,emails.value,active.GET /scim/v2/Users/{id}— read single. ReturnsETagheader.PUT /scim/v2/Users/{id}— full replace. RequiresIf-Match: <etag>; mismatch returns412 Precondition Failed.PATCH /scim/v2/Users/{id}— partial update via Operation list. Common ops: setactive: falseto soft-deprovision.DELETE /scim/v2/Users/{id}— hard delete. Most IdPs prefer to setactive: falseinstead.
Groups
POST /scim/v2/Groups/— create a group.GET /scim/v2/Groups/— list.GET /scim/v2/Groups/{id}— read.PUT /scim/v2/Groups/{id}— full replace includingmemberslist.PATCH /scim/v2/Groups/{id}— partial update. Most IdPs PATCH group membership as the user joins/leaves.DELETE /scim/v2/Groups/{id}— hard delete.
ServiceProviderConfig
GET /scim/v2/ServiceProviderConfig— capability advertisement. Vigilo advertises: PATCH supported, ETag supported, filter supported, pagination supported (50 default, 1000 max), bulk NOT supported.
ScimToken auth
ScimToken is a row in the database with workspace, token_hash, created_by, created_at, last_used_at. The plaintext token is shown once at creation (prefixed scim_) and is hashed at rest. Every SCIM request must include Authorization: Bearer scim_...; mismatch returns 401.
Tokens never expire automatically (IdPs are typically long-lived integrations). Rotate manually from Settings → SCIM; deleting the old token after the IdP picks up the new one.
JIT provisioning on group membership (WB.12)
When an IdP adds a user to a SCIM group, Vigilo can automatically create the corresponding WorkspaceMembership based on OIDCGroupMapping rows. This is just-in-time (JIT) provisioning: the user never has to manually accept a workspace invite, and the workspace never has stale members an admin forgot to remove.
The flow:
- IdP PATCHes
/scim/v2/Groups/{id}to add user X to groupeng-prod. - SCIM endpoint creates the Group membership record.
- Vigilo looks up
OIDCGroupMappingrows wheregroup_name='eng-prod'. For each match (which has a targetworkspaceandrole), Vigilo upserts aWorkspaceMembershipfor user X with that role. - If the user already has a membership with a different role, the JIT update replaces it. The audit log records both the old and new role.
The reverse is symmetric: removing a user from the SCIM group removes the corresponding WorkspaceMembership (unless that membership was created manually outside JIT, which is preserved).
OIDCGroupMapping (WB.13)
OIDCGroupMapping is the rule table that connects IdP groups to workspace memberships. Fields:
group_name— IdP-side name (matched against SCIM GroupdisplayNameor OIDC tokengroupsclaim)workspace— target workspacerole— target built-in rolecustom_role— optional FK if you want to grant a custom role instead
Mappings are workspace-scoped, but a single group_name can have mappings in many workspaces — useful when an IdP group covers multiple Vigilo workspaces (e.g. eng-leadership should be admin in engineering-tools AND viewer in marketing-tools).
When a SCIM group changes, all matching mappings are evaluated, so one IdP group update can sync membership across many workspaces.
Common workflows
1. Configure Okta to provision Vigilo
- In Vigilo: Settings → SCIM → New token. Copy the
scim_...token. - In Okta: Applications → Add SCIM 2.0 app. Base URL:
https://{vigilo-host}/scim/v2/. Auth: Bearer, paste the token. - In Okta: enable Create, Update, Deactivate user push. Enable Push Groups.
- In Vigilo: Settings → OIDC group mappings → New mapping. Map IdP group
eng-prodto workspaceprodwith roleengineer. - Assign Okta groups to the SCIM app. Within a few minutes, members appear in the right Vigilo workspaces.
2. Configure Azure AD
Same shape as Okta. Azure AD calls SCIM "Provisioning" inside the Enterprise Application; otherwise identical.
3. Audit a deprovisioning
- Open the audit log filtered by
target_type=WorkspaceMembershipandaction=delete. - Each row shows the SCIM token name that initiated the delete and the underlying group change that triggered it (via the
metadataJSON field).
4. Rotate the SCIM token
- Settings → SCIM → New token. Update the IdP to use the new token.
- Watch Settings → SCIM → Tokens for
last_used_atto confirm the IdP has switched. - Delete the old token.
Permissions
| Action | Role |
|---|---|
| Create / delete SCIM tokens | Owner |
Manage OIDCGroupMapping rows |
Admin / Owner |
| SCIM API calls themselves | The token's workspace scope only |
A SCIM token is workspace-scoped — it can only provision members into the workspace that created it. There is no installation-wide SCIM token.
Troubleshooting
Okta says "Provisioning failed: 401". Token wrong or workspace mismatch. Confirm the token in Settings → SCIM matches what Okta has.
Members appear but with the wrong role. Check OIDCGroupMapping. Missing mapping → default to viewer. Multiple mappings for the same group → the most recently created one wins.
Deprovisioning didn't remove the user from one workspace. That membership was created manually, not via JIT. Manual memberships are preserved on group removal by design — an admin must delete them explicitly. Look for membership rows where metadata.created_by_jit=False.
Group PATCH returns 412 Precondition Failed. Stale If-Match. IdP re-reads the group, retries with the new ETag — most IdPs handle this automatically.
Filter expression returns 400. Vigilo supports eq, ne, co, sw, pr and AND/OR. More exotic filters (e.g. complex grouping) are not supported; the IdP may be using an extended syntax. Configure the IdP to use only the basic operators.
Related articles
- SAML and SSO — the auth side; SCIM is the provisioning side.
- RBAC and tenancy — what the provisioned member can do.