Command Palette
Search for a command to run...

SCIM v2 provisioning

SCIM lets your IdP (Okta, Entra ID, Keycloak, …) push users and groups into Power Manage instead of waiting for first sign-in. It complements SSO: SSO authenticates, SCIM provisions and — critically — deprovisions. Both paths emit the same event types the web UI does, so the audit trail is uniform regardless of where a change came from.

Enabling SCIM on a provider

EnableSCIM is a per-identity-provider switch. It generates a 32-byte random bearer token (64 hex chars), stores only a bcrypt hash of it, and returns the plaintext token exactly once together with the endpoint URL (<base>/scim/v2/<slug>). There is no way to read the token again — losing it means rotating it.

RotateSCIMToken mints a fresh token the same way (again shown once, again only the hash stored), immediately invalidating the old one. DisableSCIM turns the endpoint off for the provider; both require SCIM to actually be enabled and fail with FailedPrecondition otherwise.

The endpoint surface

All routes mount under /scim/v2/{slug}/…: discovery (ServiceProviderConfig, Schemas, ResourceTypes), Users (list/create/get/replace/patch/delete), and Groups (same verbs). Every route — including discovery — goes through bearer-token authentication.

Authentication verifies the bearer token against the stored bcrypt hash of a SCIM-enabled, login-enabled provider. Unknown slug, SCIM-disabled provider, missing token config, and wrong token all return an identical 401 with a dummy bcrypt compare, so a client can't distinguish "slug exists" from "wrong token" by message or timing. Two rate-limit buckets run before the bcrypt work: 100/min per provider slug and 20/min per (slug, client IP).

Discovery advertises what's actually implemented: PATCH and filtering (max 200 results) are supported; bulk operations, password sync, sorting, and ETags are not.

How SCIM maps to Power Manage objects

Rendering diagram…

POST /Users has four outcomes: an externalID that's already linked re-syncs and returns 200 (idempotent for clients that re-POST every sync cycle); with auto_link_by_email on, an already-linked email re-syncs (200) and an unlinked existing user gets an identity link (201); a genuinely new user is created passwordless with a derived Linux username/UID, the provider's default role, and an identity link. If the global server settings have provisioning or SSH-for-all enabled, the new user inherits those flags immediately.

PUT and PATCH /Users/{id} sync email, name fields, and the active flag — active: false disables the user (blocking login), active: true re-enables. Ownership is enforced first: a provider can only touch users it holds an identity link for; anything else is a 404. PATCH supports replace ops (add/remove are rejected with a 400).

POST /Groups creates a regular Power Manage user group plus a SCIM group mapping (provider + SCIM group ID → user group ID). Re-POSTs are idempotent: display-name changes sync through, and a members array — when present — is reconciled against current membership. Members are added by user ID and only if the provider owns them.

Deprovisioning

DELETE /Users/{id} first removes the provider's identity link. Only if that was the user's last link is the user actually deleted — a user linked to other providers (or usable via password) keeps their account. On a real deletion, the user's system actions (provisioned Linux accounts, SSH grants, TTY accounts) are cleaned up from their assigned devices.

DELETE /Groups/{id} removes only the SCIM mapping — the underlying user group survives, with its members and role grants intact. IdP-side group deletion never cascades into deleting a group an operator may have wired into RBAC.

Provisioning toggles: what actually gets gated

Two flags share a name but gate the same thing at different granularity — whether a user's Linux account is provisioned on their assigned devices (the system USER action):

The system-action sync provisions a user's Linux account when ServerSettings.user_provisioning_enabled (global) or the user's own user_provisioning_enabled flag is set; when neither holds, existing provision actions are cleaned up. Neither flag affects SCIM or SSO account creation itself — a user can exist in Power Manage without ever materialising on a device.

SetUserProvisioningEnabled flips the per-user flag (scope-enforced: :self-scoped callers can only toggle themselves); the post-commit listener then re-syncs that user's system actions.

The global ServerSettings.user_provisioning_enabled (via UpdateServerSettings) is additionally a batch enable: turning it on fans out and sets the per-user flag on every existing user. Turning the global flag off does not clear those per-user flags — users provisioned under the global setting stay provisioned until toggled off individually.