SCIM provisioning

System for Cross-domain Identity Management (SCIM) is a standard protocol for automating user and group provisioning. Posit Connect implements SCIM v2.0, enabling identity providers (IdPs) like Okta and Microsoft Entra ID to manage users and groups programmatically.

SCIM provisioning is available across all Connect license tiers.

Prerequisites

  • Configure Connect with SAML or OpenID Connect (OIDC) authentication. SCIM does not support LDAP, PAM, password, or proxy authentication.
  • Create a service token with the identity:manage scope. Your IdP uses this token to authenticate with Connect.

Enabling SCIM

Add the appropriate setting for your authentication provider:

/etc/rstudio-connect/rstudio-connect.gcfg
; For SAML authentication:
[SAML]
EnableSCIM = true

; For OIDC authentication:
[OAuth2]
EnableSCIM = true

Restart Connect after changing this setting.

Authentication

The discovery endpoints (/scim/v2/ServiceProviderConfig, /scim/v2/Schemas, /scim/v2/ResourceTypes) are publicly accessible. All other SCIM endpoints require authentication via a service token with the identity:manage scope.

Create a service token following the service token documentation, then enter the token value in your IdP’s SCIM configuration. The IdP uses this token to authenticate its requests to Connect by passing it in the Authorization header:

Example request
curl -H "Authorization: Bearer SERVICE-TOKEN" \
  https://connect.example.com/scim/v2/Users

Identity provider setup

When configuring SCIM provisioning in your IdP, provide these Connect-specific values:

Setting Value
SCIM endpoint URL https://connect.example.com/scim/v2
Authentication method HTTP Header (Bearer token)
Token A service token with identity:manage scope

For IdP-specific setup instructions, refer to your provider’s documentation:

The externalId attribute

The externalId attribute maps to the Connect internal unique ID, the unique identifier that links a Connect user account to the corresponding identity in your IdP.

Your IdP sends externalId automatically in SCIM provisioning requests when it creates or updates users. The value it sends should match the unique ID that Connect stores when users authenticate:

Check the SCIM attribute mappings in your IdP to verify which value it sends as externalId, and ensure it matches the corresponding Connect setting above.

When externalId is set correctly, Connect can correlate SCIM-provisioned users with authenticated sessions. This also allows your IdP to locate existing Connect users by filtering on externalId.

Enabling SCIM on existing instances

When you enable SCIM on a Connect instance that already has users and groups, your IdP must discover those existing accounts before it can manage them. These users might have been created via SSO logins, the API, or manually.

How Connect handles discovery requests

Most IdPs discover existing users by querying the SCIM endpoint with a filter. Connect supports filtering by userName and externalId:

  • userName: Connect performs a case-insensitive match per RFC 7644 §3.4.2.2. A user created as “Alice.Smith” is found when the IdP queries for “alice.smith”. If a match is found, the IdP can immediately manage that user via PUT/PATCH using the returned id (GUID).
  • externalId: Connect matches against the user’s stored unique ID. If the user was created through SSO login, their unique ID is typically the SAML NameID or OIDC sub claim. If the IdP sends a different value as externalId, the filter returns zero results.

The exact discovery flow varies by IdP. Consult your IdP’s SCIM provisioning documentation for details on its matching behavior.

Unique ID mismatch

When a filter returns zero results, the IdP typically attempts POST /Users to create the account. Connect returns 409 Conflict if a user with the same userName already exists. The user becomes stuck: the IdP cannot find them by externalId filter (because the stored unique ID does not match) and cannot create them (because the username is taken).

Resolution

For each stuck user, update their unique ID in Connect to match the value your IdP sends as externalId. Use the usermanager alter --new-unique-id CLI command on the Connect server.

To determine what value your IdP sends, check its SCIM attribute mappings and provisioning logs. Some IdPs also let you trigger a test provisioning cycle for a single user, which shows the exact request.

Important

To avoid this problem entirely, align unique IDs before enabling SCIM. Update all existing users’ unique IDs to match what your IdP will send as externalId using the usermanager alter --new-unique-id CLI command.

Guarantees Connect provides

  • Role preservation: SCIM operations on pre-existing users do not change their Connect role. A publisher who is locked or unlocked via SCIM retains their publisher role throughout.
  • Content preservation on deactivation: When a user is deactivated via SCIM (setting active to false), the user’s account is locked. Content owned by the locked user remains available and scheduled reports continue to execute. The user cannot sign in or deploy new content until reactivated.
  • Data safety on conflicts: When a POST /Users request returns 409 Conflict, the existing user’s data is not modified. The existing user’s name, email, role, and unique ID remain unchanged.

Interaction with other features

User registration

Users created via SCIM can log in immediately, regardless of the value of the RegisterOnFirstLogin setting.

If RegisterOnFirstLogin is false, users must be pre-provisioned via SCIM or the API before they can log in, even if their single sign-on flow is otherwise successful.

User roles

SCIM does not support setting or changing user roles. Users created via SCIM are assigned the role specified by Authorization.DefaultUserRole, which defaults to viewer.

To assign a different role to SCIM-provisioned users, you have two options:

  • Change the default role for all new users: Set Authorization.DefaultUserRole to publisher in your Connect configuration. This affects all newly created users, not just those provisioned via SCIM. The only accepted values are viewer (default) and publisher.

    /etc/rstudio-connect/rstudio-connect.gcfg
    [Authorization]
    DefaultUserRole = publisher
  • Change individual user roles after provisioning: Use the Connect UI or the Connect API to update a specific user’s role after SCIM creates their account.

SCIM operations on pre-existing users (such as locking or unlocking) do not change their role. A publisher who is deactivated and later reactivated via SCIM retains the publisher role throughout.

Group provisioning

SCIM and authentication-based group provisioning (via SAML assertions or OIDC claims) both operate on the same underlying groups in Connect. They can coexist, but two interactions need attention: duplicate groups and membership conflicts.

Duplicate groups

When GroupsByUniqueId is enabled, Connect identifies groups by unique ID rather than name and does not enforce unique group names. This means multiple groups can share the same display name if they have different unique IDs. SCIM assigns its own unique ID when it creates a group (derived from the IdP identifier). If the same logical group is also created through the Connect Server API with a different unique ID, two groups with the same display name appear in the Connect UI. Each group has different members and permissions.

Note

The Connect configuration validation prevents GroupsByUniqueId and GroupsAutoProvision from being enabled simultaneously. However, duplicates can still occur when groups are created through multiple channels (SCIM, the API, or the CLI) with different unique IDs.

To avoid duplicates:

  • Use only one provisioning system for groups (SCIM or authentication-based, not both).
  • When creating groups through the API while SCIM is active, verify that a group with the intended name does not already exist.
  • If duplicates already exist, delete the unwanted group and migrate its members and content permissions to the group you want to keep.

Membership conflicts

Both systems can add and remove group members, and neither is aware of the other’s changes. In both cases, the most recent operation wins:

  • Membership removal at login: When SAML.GroupsAttribute or OAuth2.GroupsClaim is configured, each login sets the user’s group membership to match exactly what appears in their assertion or token. If SCIM added the user to a group that is not present in their login assertion, the authentication provider removes them from that group. There is no separate toggle to disable this removal. It is an inherent behavior of configuring group claims.
  • Membership replacement via SCIM: When an IdP sends a SCIM replace members operation, Connect sets the group’s member list to exactly what the IdP specifies. Users added to the group through authentication-based provisioning are removed if they are not in the IdP member list.

To avoid unexpected membership removal, use one system or the other for group management. If you must use both, ensure that your IdP sends identical group assignments through SCIM and through login assertions.

License enforcement

When a user is reactivated via SCIM (setting active to true), Connect checks the license seat limit. If the limit is exceeded, Connect logs an error but still returns a successful response to the IdP. The reactivated user is blocked at login time instead.

This behavior prevents IdP sync failures caused by unexpected HTTP error codes. Monitor Connect logs for license limit warnings if you are near capacity. See the license capacity page for monitoring details.

Troubleshooting

Connection test fails

IdPs will sometimes validate that your SCIM credentials can successfully authenticate against Connect during setup. If this connection test fails:

  1. Confirm SCIM is enabled in your configuration.
  2. Verify the SCIM endpoint URL is https://<your-connect-server>/scim/v2.
  3. Check that the service token has the identity:manage scope.
  4. Ensure network connectivity between your IdP and Connect.
  5. Check Connect logs for authentication errors.

IdP cannot find or create pre-existing users (repeated 409 errors)

This occurs when your IdP filters by externalId and the value does not match the unique ID stored in Connect. The filter returns zero results, the IdP attempts to create the user via POST, and Connect returns 409 because the username is taken. Some IdPs might pause or throttle provisioning after sustained failures.

To resolve:

  1. Check your IdP’s provisioning logs to identify which users are failing with 409.
  2. Determine what value your IdP sends as externalId (check its attribute mappings).
  3. For each affected user, update their unique ID in Connect to match. Use the usermanager alter --new-unique-id CLI command on the Connect server.
  4. Restart or resume provisioning in your IdP.

See Enabling SCIM on existing instances for background on why this happens and how to prevent it.

Duplicate groups in the Connect UI

If you see two groups with the same name in the Connect UI, this is likely caused by running both SCIM and authentication-based group provisioning with GroupsByUniqueId enabled. See Duplicate groups with GroupsByUniqueId enabled for an explanation and resolution.

See also