LumiBaseDocs

SCIM 2.0 Provisioning

LumiBase implements a subset of RFC 7644 — enough for Okta, Azure AD, Logto and Google Workspace to provision and deprovision users and groups automatically.

Endpoints

Mounted at /scim/v2/* (outside /api/v1):

EndpointMethodPurpose
/scim/v2/UsersGETList with a filter (e.g. userName eq "alice@x.com")
/scim/v2/Users/:idGETGet a user
/scim/v2/UsersPOSTCreate a user
/scim/v2/Users/:idPUTReplace a user
/scim/v2/Users/:idPATCHPartial update
/scim/v2/Users/:idDELETESoft delete (active: false)
/scim/v2/GroupsGETList groups (= LumiBase teams)
/scim/v2/GroupsPOSTCreate a group
/scim/v2/ServiceProviderConfigGETCapabilities advertisement
/scim/v2/SchemasGETSchema definitions
/scim/v2/ResourceTypesGETResource types

Implementation: apps/cms/src/routes/scim.ts.

Auth & security (token rotation)

SCIM does not authenticate through the Logto JWT pipeline for end-user identity. It uses its own bearer tokens instead:

  • Stored securely: the actual token is hashed with SHA-256 before being written to the scim_tokens table. The plaintext token is shown exactly once, at creation.
  • Rotation: a new token can be issued and the old one revoked. On rotation the old token keeps a 24-hour grace period before expiring completely, so the integration is not interrupted.
  • Audit logging: every SCIM configuration change (create user, edit group, delete, …) is recorded automatically in the activity log, tagged with the label of the token that performed it.

SCIM token management APIs (require a Logto JWT):

  • POST /api/v1/scim-tokens: mint a new token (returns the plaintext once only).
  • GET /api/v1/scim-tokens: list issued tokens (partially redacted — metadata only).
  • DELETE /api/v1/scim-tokens/:id: revoke a token immediately.
  • POST /api/v1/scim-tokens/:id/rotate: rotate a token (issue a new one and set the 24h grace period on the old one).

Mapping

SCIMLumiBase
User.userNameusers.email
User.name.givenName / familyNameusers.firstName / lastName
User.activeusers.status (activesuspended)
Groupa teams row
Group.membersteam_members rows

Schema URNs

code
urn:ietf:params:scim:schemas:core:2.0:User
urn:ietf:params:scim:schemas:core:2.0:Group
urn:ietf:params:scim:api:messages:2.0:ListResponse
urn:ietf:params:scim:api:messages:2.0:Error

Response format

json
{
  "schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
  "id": "u_abc123",
  "userName": "alice@example.com",
  "name": { "givenName": "Alice", "familyName": "Doe" },
  "active": true,
  "meta": { "resourceType": "User", "created": "...", "lastModified": "..." }
}

IdP configuration

Okta

  • SCIM 2.0 Connector Base URL: https://<your-cms>/scim/v2
  • Auth: HTTP header Authorization: Bearer <SCIM_TOKEN>
  • Push Profile Updates and Push Groups: enabled.

Azure AD

  • Tenant URL: https://<your-cms>/scim/v2
  • Secret token: <SCIM_TOKEN>
  • The default mappings work with LumiBase users/groups.

Multi-tenancy & isolation

SCIM is designed to be fully isolated between tenants:

  • Token-based site extraction: the middleware resolves the siteId bound to the token directly from the database.
  • Spoofing prevention: the system ignores any client-supplied X-Lumi-Site header, so a tenant cannot be spoofed. Every resource (Users, Groups) created or modified is strictly confined to that token's site.
Last modified: 24/08/2026