Skip to content

SCIM Provisioning

Melvin PETIT edited this page Jun 16, 2026 · 1 revision

SCIM Provisioning

SCIM 2.0 is the inbound, push-based alternative to the pull connectors in Directory Integrations. Instead of DataShield fetching users, your identity provider pushes user create/update/delete events to DataShield as they happen.

Endpoints

A SCIM connection exposes a per-connection base URL:

/api/scim/[connectionId]/Users           # list, create
/api/scim/[connectionId]/Users/[scimId]  # get, replace, delete

connectionId is the id of a DirectoryConnection whose type is SCIM.

Authentication

Every SCIM request is authenticated by a bearer token stored (encrypted) in the connection config. authenticateScim in directory/scim-auth.ts:

  1. Reads the Authorization: Bearer <token> header.
  2. Looks up the SCIM connection by id.
  3. Decrypts the stored config and compares the token using constant-time comparison (crypto.timingSafeEqual) to neutralize timing attacks.
  4. Returns the associated companyId, or null (which the routes turn into 401). It never throws: an unreadable config also yields 401, never 500.

Setup outline

  1. Create a SCIM directory connection in DataShield (generates the bearer token and the per-connection base URL).
  2. In your IdP's provisioning settings, enter the base URL and bearer token.
  3. Assign users/groups so the IdP starts pushing provisioning events.

DataShield maps incoming SCIM users to the normalized DirectoryUser shape and upserts them into the Employee table, scoped to the connection's company.

Why SCIM vs pull sync

  • Pull connectors (Entra, Google, LDAP, AWS, Okta) fetch the full directory on demand; good when you control the schedule.
  • SCIM keeps the directory continuously in sync with no polling, driven by the IdP lifecycle (joiner / mover / leaver). Triggering a manual pull-sync on a SCIM connection is rejected by design.

Clone this wiki locally