Provisioning with SCIM
The identity provider creates, updates and deprovisions accounts and keeps workspace roles in step with its groups: what to check first, the token, the steps at each provider, and the endpoints Ronne serves.
Describes Ronne AI Marketplace 0.4.0.
Provisioning with SCIM
With SCIM, the identity provider creates, updates and deprovisions Ronne accounts by itself, and keeps workspace roles in step with its groups. When someone leaves, the provider disables their account at its next sync: their sessions and access tokens end at once, without root remembering to do it. Deprovisioning disables an account; it never erases one, so the person's published items keep their record.
SCIM is set up per provider, on the provider's page under Admin › Settings › Authentication, in the Provisioning (SCIM) section. It doesn't need the provider's sign-in to be on, but people created by SCIM have no password: they sign in through the provider.
Before you turn it on
- Emails match. The provider sends each person's email as
userName. Someone whose Ronne email differs from it gets a second account, which they can't sign in to, while their first stays outside SCIM. Change those emails in Users first; if a second account was made anyway, erase the second after fixing the email. - Existing accounts are adopted only when it's safe. When the provider creates someone who already has an account, Ronne takes that account over only if its email is exactly the
userName, the person signed in through this provider in the last 30 days, it has never been linked by SCIM before, the account isn't root, and it is enabled. Otherwise the provider gets a conflict (409) and the account is left as it is. So have people sign in through the provider in the 30 days before you start provisioning. - Groups are assigned in SCIM. From now on SCIM is the one source of this provider's groups (SCIM groups and workspace roles). Roles the sign-in gave stay until the provider's first group change that includes the person, so push the mapped groups.
- Leavers are already disabled. Someone who left before SCIM, or who isn't assigned to it at the provider, is never deprovisioned by it: disable them in Users.
Turning it on, and the token
- Turn on SCIM, and confirm. The section shows the base URL,
https://ronne.example.com/api/v1/scim/v2, with Copy. - Generate token. It starts with
scim_and is shown once: Ronne keeps only its hash. Paste it into the provider's SCIM settings, as a Bearer token. - Follow your provider's steps below, then start provisioning there.
The section says when the token was made, by whom, and when it was last used. Rotate makes a new token and keeps the current one working for 24 hours, so you can change it at the provider calmly. Revoke stops it at once, and the one before a rotation too. Turn off SCIM refuses every request at once and keeps the accounts, the links, the groups and the token, for when you turn it on again. A request with a wrong, revoked or old token is refused with 401, and the refusal is in the audit log.
What the provider does to accounts
- Create: a new account, a user in
globalwith a personal workspace and no password, never root. Its name and email come from the provider. - Update: the name and the email. While SCIM is on, the provider is their only source: Users has no way to edit them, and the provider's next sync puts back what it says.
- Deactivate (
active: false): the account is disabled, its sessions end and its access tokens are revoked, in one step. The next page it opens is the sign-in page, andrmkgets 401. Its workspace roles stay. Reactivate (active: true) enables it again; it signs in again, and its revoked tokens stay revoked. - Delete: the account is disabled the same way, it loses every workspace role the provider gave, and SCIM lets go of it. It stays in Ronne, marked Deprovisioned by <provider>, disabled. If the provider creates the same person again (the same
externalId), the same account comes back, enabled. Root can then erase it from its page: unassign the person at the provider first, or its next sync creates a new, empty account. - Root is never touched: a request about a root account is refused, and a root in a group is left out. Root accounts are managed in Ronne.
In Users, these accounts show Managed by <provider>, an adopted one Adopted by <provider> on <date> as well, so you can review each adoption, and a deleted one Deprovisioned by <provider> on <date>. On the user's page, Disable and Enable still work, but a notice warns that the provider's next sync sets them back: change it at the provider. Reset password gives one of these accounts a password, for when the provider can't sign people in.
SCIM groups and workspace roles
The provider's SCIM groups give workspace roles through the same mappings as its sign-in (Groups and workspace roles), and by the same rules: a mapped group gives its workspace at least the mapped role, the higher of two wins, a hand-set membership is never changed, nor is root, and nobody leaves global. A mapping matches a group's name or its externalId, exactly, so mappings made for Entra's groups claim (object IDs) keep working.
- When the provider adds someone to a group, removes them, renames the group or deletes it, the roles of the people it changes follow at once.
- While SCIM is on, this provider's sign-in no longer applies its groups claim: SCIM is the one source. Turned off, the sign-in applies it again.
- Turning SCIM on, or adopting an account, changes no role. Roles the sign-in gave stay until the provider's first group change that includes the person, which applies the mappings from the SCIM groups.
- A deleted person loses every role the provider gave at once; a deactivated one keeps them while disabled.
- A group no mapping names is kept and gives nothing.
Each change is in the audit log as a member change, marked as the provider's.
Microsoft Entra ID
- In the Entra admin center, Entra ID › Enterprise apps, open the application for Ronne (or New application › Create your own application, not from the gallery), then Provisioning.
- Make a new configuration with Bearer authentication: the base URL as the Tenant URL and the token as the Secret Token. Test Connection, then create it.
- In Attribute mapping, for users, map
objectIdtoexternalId. Entra's default,mailNickname, is an alias that can be given to someone new, who would then come back as the old account. Groups'externalIdis already theirobjectId. - Assign the users and groups to provision in Users and groups, then Start provisioning. Entra syncs about every 40 minutes; Provision on demand does one person now.
Entra sets active to false when someone is unassigned or disabled, and deletes them when they're deleted for good.
Okta
- Open the application for Ronne (the OIDC one from Okta). On its General tab, edit App Settings and choose SCIM as Provisioning.
- On the Provisioning tab, Integration: the base URL as the SCIM connector base URL,
userNameas the unique identifier field for users, the actions Push New Users, Push Profile Updates and Push Groups, and HTTP Header authentication with the token. - Under To App, turn on Create Users, Update User Attributes and Deactivate Users.
- Assign the people, then push the groups Ronne maps, on the Push Groups tab.
Okta deactivates people (active: false) and doesn't delete them.
authentik
- Applications › Providers › Create › SCIM Provider, with the base URL as its URL and the token as its token.
- Edit the application for Ronne and add the SCIM provider under Backchannel Providers. authentik then sends Ronne the people the application is bound to (everyone, when it's bound to no one) and the groups, when they change and once an hour.
Keycloak
Keycloak can't send SCIM by itself. A community extension that provisions users and groups to a SCIM server can: install one in Keycloak and give it the base URL and the token as a Bearer token. Keycloak's team doesn't support those extensions, so test one before relying on it.
Auth0
Auth0 has no SCIM client to provision another application: its SCIM is for receiving users. Its Event Streams can drive your own code that calls Ronne's SCIM; otherwise people get their accounts by signing in through Auth0, and leavers are disabled in Users.
Other providers
Give the provider the base URL and the token as a Bearer token. It must send the person's email as userName, and as externalId an id that never changes and is never given to someone else. The group mappings match a group's name or its externalId. The SCIM endpoints say what Ronne accepts.
SCIM endpoints
Ronne serves SCIM 2.0 (RFC 7643 and 7644) at https://ronne.example.com/api/v1/scim/v2, for the providers' clients. Every request but discovery needs Authorization: Bearer scim_…; answers are application/scim+json, and errors use SCIM's error format.
| Path | What it takes |
|---|---|
ServiceProviderConfig, ResourceTypes, Schemas | GET, without a token: what Ronne supports, and the core User and Group. |
Users | GET (a page of 100 at most, with startIndex and count, and a filter) and POST. |
Users/<id> | GET, PUT, PATCH and DELETE. |
Groups, Groups/<id> | The same; excludedAttributes=members leaves the members out. |
- Filters:
eqonly: onuserName,externalIdandidfor Users, and ondisplayName,externalIdandidfor Groups. Emails are compared in lower case. - Users take
userName(the email, plain ASCII),nameordisplayName,externalIdandactive, and a PATCH ofemailschanges the email; other attributes are ignored. Roles, passwords and a user's groups are read-only: membership changes through Groups. The id is the SCIM link's, not the account's; after a DELETE it answers 404 everywhere. - PATCH takes
add,replaceandremove, with a path or as a value object, as Entra and Okta send them;"False"is read as false. Groups' members are SCIM user ids, removed one by one withmembers[value eq "…"]. - Errors: 400 for a bad request (
invalidValue,invalidSyntax,invalidFilter,invalidPath,noTarget,mutabilityfor removingactive,userNameor a group'sdisplayName), 401 for any token problem or SCIM off, 403 for a root account, 404, 405 for a method a path doesn't take, 409uniquenessfor auserName, email orexternalIdalready used, 413 and 415 for a body too large or not JSON, and 429 withRetry-Afterpast 600 requests a minute per token. - Not supported: bulk operations and
/Me(501), sorting, ETags and changing passwords.