Skip to content

SCIM docs don't explain the feature surface, and repeat a stale 40-char team-name limit #20943

Description

@jkodroff

Problem

The SCIM docs are organized as three provider setup walkthroughs with no shared statement of what SCIM actually does. A reader can't answer basic questions ("can SCIM assign roles?", "does deprovisioning delete the user?", "will my IdP work?") without reading all three pages and inferring. Several cross-provider facts are stated on exactly one page, which makes them read as provider-specific quirks when they're universal.

Verified against the implementation in pulumi/pulumi-service (cmd/service/api/scim/, cmd/service/api/{users,teams}_scim*.go, routes at cmd/service/main.go:1652-1692).

Pages in scope:

  • /docs/administration/access-identity/scim/ (_index.md)
  • /docs/administration/access-identity/scim/okta/
  • /docs/administration/access-identity/scim/entra/
  • /docs/administration/access-identity/scim/onelogin/
  • /docs/support/faq/scim/

Key context: SCIM is provider-agnostic

Unlike VCS integrations, there is one SCIM 2.0 implementation. Every IdP hits the same routes, schemas, attributes and limits. There is no per-provider config, no capability matrix, and no supported-provider enum in the codebase. Only the IdP-side setup differs.

The only two places an IdP affects server behavior are compatibility accommodations available to everyone: GET /Users is registered for search because some IdPs only search via GET, and a userName reactivation quirk is tolerated leniently.

Practical implication: any spec-compliant SCIM 2.0 IdP should work, not just the three we document. The docs currently read as if those three are the only options. (Flagging that this is a support-commitment statement — worth product sign-off on how strongly to word it.)

Bugs to fix

  • Stale team-name limit. All three provider pages warn that team names "must not exceed 40 characters". The real limit is 100 (maxDefaultNameLength = 100, enforced in teams_scim.go:549; column widened 40→100 by migrations/328_bump_scim_display_name_size.up.sql in Nov 2024). Stale for ~21 months. Locations: okta.md:143, entra.md:33, onelogin.md (group provisioning section).
  • Broken anchor. onelogin.md:20 links to #known-limitations, but the OneLogin page has no such section. Okta and Entra both do.
  • FAQ attribute list is incomplete. The "Unknown path" answer lists userName, displayName, givenName, familyName, active — it omits emails[type eq "work"].value, which is supported and which the Entra guide tells you to mark as required.
  • Entra intro undersells scope. It says "provisioning/deprovisioning of your users"; Okta and OneLogin say "users and groups". Entra supports groups, and the page already has a group-provisioning section.

Add a capability section to the SCIM index page

_index.md is 32 lines and documents no feature surface at all. Proposed content:

Supported

Capability Notes
User provisioning Create, read, update (PUT/PATCH), search
User deprovisioning Soft onlyactive: false. There is no DELETE /Users.
Group → Pulumi Team sync Create, read, update, delete, membership add/remove/replace
PATCH Supported for both Users and Groups
Filtering userName eq (Users) and displayName eq (Groups) only; eq is the only operator
Pagination Users only. Max 100/page. Group search returns all results in one response.

Supported attributes — this is the complete list

  • Users: userName (immutable after creation), displayName, name.givenName, name.familyName, emails[type eq "work"].value, active
  • Groups: displayName, members

Anything else returns 400 invalidPath.

Not supported

Notes
Role / admin provisioning No roles or entitlements. Org role and team role can't be set via SCIM; SCIM users are always created as members and team members are always added as plain members.
externalId Accepted on Users but never stored; Groups have no externalId field at all. This is why the Entra guide says to delete the objectIdexternalId group mapping.
Bulk operations bulk: false
Sorting sort: false
ETag etag: false
Password sync changePassword: false
Enterprise User extension Core 2.0 schemas only
Secondary emails Only the primary work email is used

Editions

Business Critical (Pulumi Cloud) and self-hosted Enterprise.

Promote single-page facts to the shared page

These are universal but currently appear on one page each:

  • Deprovisioning never deletes. OneLogin's "Suspend (DO NOT set to Delete)" is the only place this appears, but it's true for every IdP — there is no DELETE /Users route at all. Okta and Entra readers never learn this.
  • userName is immutable after creation. Okta's page explains the "Create only" mapping and Entra's explains "Only during object creation"; neither says why, and OneLogin doesn't mention it.
  • Group members must already be provisioned and active before the group is pushed, or the request returns 400. Currently only in the Okta page and the FAQ.
  • externalId on groups is ignored — documented only on the Entra page today, universal in fact.

Also worth a warning

GET /Groups returns all teams matching the display-name filter, including Pulumi-local and GitHub-backed teams, not only SCIM-provisioned ones (cmd/service/model/teams.go:515-523). Since the docs explicitly encourage running local teams alongside SCIM teams, an IdP reconciling group state may see teams it doesn't own.

Group member validation also caps at 3000 SAML identities per query, which is an undocumented practical ceiling on team size.

Related

Metadata

Metadata

Assignees

Labels

Type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions