SCIM 2.0 provisioning

OneAnalytics implements SCIM 2.0 for automated user and group provisioning. Pair it with SAML SSO for a complete identity story — SSO authenticates, SCIM manages lifecycle.

Endpoints

Base URL: https://api.analytics.rstglobal.in/scim/v2

ResourceVerbs
/UsersGET (list, filter), POST
/Users/{id}GET, PUT, PATCH, DELETE (soft)
/GroupsGET (list, filter), POST
/Groups/{id}GET, PUT, PATCH, DELETE
/ServiceProviderConfigGET
/SchemasGET
/ResourceTypesGET

All responses are application/scim+json and errors follow the SCIM error envelope (not RFC 7807), per the spec.

Authentication

Per-tenant bearer token. Generate in Settings → SCIM → New token. Store in your IdP's SCIM integration config. Tokens can be revoked independently of user passwords.

Provider walkthroughs

Okta: App → Provisioning → Integration → Enable API Integration → paste base URL + bearer token → map attributes → enable Create users, Update user attributes, Deactivate users.

Azure AD: Enterprise Application → Provisioning → Automatic → paste Tenant URL = <base> + Secret Token = <bearer>Test → map attributes → enable provisioning.

JumpCloud: App → SCIM → enable → paste base + token → map.

Filter grammar

We accept the SCIM filter subset most IdPs emit:

  • userName eq "ada@example.com"
  • emails.value eq "ada@example.com"
  • displayName sw "Ada"
  • active eq true
  • members[value eq "<user_id>"] (for Groups)

Compound filters (and, or) on a single attribute work. Nested filters beyond one level are rejected with 400 invalidFilter.

PATCH operations

Full SCIM PATCH path grammar:

  • {"op": "replace", "path": "displayName", "value": "New Name"}
  • {"op": "add", "path": "members", "value": [{"value": "user-id"}]}
  • {"op": "remove", "path": "members[value eq \"user-id\"]"}

Okta and Azure emit both forms; we handle both.

Soft delete

DELETE /Users/{id} marks the user inactive (active: false) and removes team memberships. The user record is retained for 30 days in case of restore, then hard-deleted. This satisfies most IdPs' "deprovisioning confirmed" check.

Attribute → RLS

Any SCIM attribute becomes available to row-level security as user.attributes.<name>. Custom enterprise attributes (urn:ietf:params:scim:schemas:extension:...) are flattened to their terminal field name.

Troubleshooting

  • Okta shows "400 invalidValue" — Okta tries to send externalId of type bytea; we require string. Disable that attribute in the mapping.
  • Azure shows "410 Gone" — We return 410 for a DELETE of an already-deleted user (per the spec). Azure treats this as success; no action needed.