Skip to content

feat: scim group and user provisioning#8096

Draft
n1ru4l wants to merge 68 commits into
mainfrom
feat-scim-user-group-provisioning
Draft

feat: scim group and user provisioning#8096
n1ru4l wants to merge 68 commits into
mainfrom
feat-scim-user-group-provisioning

Conversation

@n1ru4l

@n1ru4l n1ru4l commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Description

This PR implements #2993, which adds:

  • Syncing groups and users from a identity provider (such as Okta or Entra) to Hive Console using SCIM 2.0
  • Assigning role + resource mappings to provisioned groups to grant users permissions based on assigned groups
  • Configure a custom claim for the OIDC identity to SCIM provisioned user identity mapping

What is still missing to get this released?

  • Manual test with all the identity providers our customers will use
  • Ensure users personal access token permissions are restricted on groups
  • Ensure provisioned user is jailed to the organization (business logic + tests)
  • Ensure provisioned user can no be modified/altered outside SCIM (business logic + tests)
  • UI for configuring user id claim
  • Polish the UI around users and groups
  • I want to cleanup the logic for creating users which is right now split into our old storage module and also the new users store I introduced

Testing the Changes

  • In order to use the SCIM endpoints, the organization needs to be set up to an OIDC provider.
  • Once that is done you can use the base endpoint http://localhost:3001/scim/v2/ for provisioning users and groups.
  • For Authorization, use a organization access token with the permissions to Modify/Manage organization members (member:modify). Send it via Bearer authentication (Header: Authorization: Bearer ACCESS_TOKEN).
  • Use your identity provider to provision users and groups
  • Within the members settings new "groups" section on the Hive dashboard you can assign role mappings to grant permissions to groups

Notes on the SCIM Endpoints

Currently, the SCIM endpoints has only been field tested against a Okta custom integration (Note: Okta also has integration network integration, which have different behaviour. More info here).

A quite extensive integration test suite exists for the endpoints (based on example payloads shared both in the documentation provided by Okta and Entra), though we can only gain 100% confidence by actually running a manual provisioning test against each identity provider as the protocol implementations and usages are quite a bit messy.

The endpoints are implemented as defensive as possible in an attempt to support a large variety of quirks the identity providers could have when calling the endpoints.

Notes on Groups

  • Groups can currently only be managed (created, updated and deleted) via the SCIM endpoints.
  • While groups have an externalId in SCIM, it seems that both Okta and Entra do not use an externalId and instead map the group via the displayName instead, thus in our implementation providing a externalId is optional and the displayName will be used as the unique property for detecting conflicts if not provided.

Resource Links

Checklist

  • Input validation
  • Output encoding
  • Authentication management
  • Session management
  • Access control
  • Cryptographic practices
  • Error handling and logging
  • Data protection
  • Communication security
  • System configuration
  • Database security
  • File management
  • Memory management
  • Testing

@n1ru4l
n1ru4l force-pushed the feat-scim-user-group-provisioning branch from 5c05cdb to 7985e93 Compare June 1, 2026 05:38

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces SCIM user and group provisioning, including database migrations, GraphQL schema updates, backend stores, and a frontend dashboard for managing groups and role mappings. Feedback highlights critical SQL syntax errors in GroupStore due to unclosed comments, and a tenant isolation vulnerability in disableGroup where updates are performed without filtering by organization. Additionally, the frontend Groups component has potential runtime crashes from unsafe property access on loading states, and contains unused mock data and placeholder alerts. Performance improvements are suggested to remove unnecessary async allocations in batch mapping functions, and database integrity can be enhanced by adding unique constraints and indexes to the migration.

Comment thread packages/services/api/src/modules/organization/providers/group-store.ts Outdated
Comment thread packages/services/api/src/modules/organization/providers/group-store.ts Outdated
Comment thread packages/web/app/src/components/organization/members/groups.tsx Outdated
Comment thread packages/web/app/src/components/organization/members/groups.tsx Outdated
Comment thread packages/web/app/src/components/organization/members/groups.tsx Outdated
Comment thread packages/services/api/src/modules/organization/providers/group-member-store.ts Outdated
Comment thread packages/services/api/src/modules/organization/providers/group-store.ts Outdated
@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

🚀 Snapshot Release (alpha)

The latest changes of this PR are available as alpha on npm (based on the declared changesets):

Package Version Info
hive 11.5.1-alpha-20260717125125-3707ec013dc6225c0b08001c88c6292d0bb75755 npm ↗︎ unpkg ↗︎

@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

🐋 This PR was built and pushed to the following Docker images:

Targets: build

Platforms: linux/amd64

Image Tags: 11.7.0-alpha-3707ec0, 3707ec0, 3707ec013dc6225c0b08001c88c6292d0bb75755

@n1ru4l
n1ru4l force-pushed the feat-scim-user-group-provisioning branch 4 times, most recently from aa43180 to 02e2a39 Compare June 11, 2026 12:00
@n1ru4l
n1ru4l force-pushed the feat-scim-user-group-provisioning branch from 18f1cab to d984c8c Compare June 14, 2026 08:16
@dotansimha
dotansimha force-pushed the feat-scim-user-group-provisioning branch from 43ed083 to c89cf3d Compare June 17, 2026 14:08
@iftika1

iftika1 commented Jul 15, 2026

Copy link
Copy Markdown

👋 Hi — really appreciate this SCIM work; it's been solid to integrate against. While validating against the SCIM 2.0 spec (RFC 7643/7644) we came across a few upstream observations we thought would be useful to share:

SCIM 2.0 conformance

  • PATCH isn't atomic (RFC 7644 §3.5.2) — in PATCH /Groups, the property-update / member-remove / member-add steps run as separate un-wrapped statements, so a partial failure isn't rolled back (only full-replace is transactional). The spec requires all-or-nothing.
  • totalResults returns the page size, not the total (RFC 7644 §3.4.2) — it's set to resources.length, so paginated clients under-collect / stop after the first page. Needs a COUNT(*) for the query.
  • meta is missing location / created / lastModified (RFC 7643 §3.1) — user and group resources return only meta.resourceType.
  • User resource has no groups[] (RFC 7643 §4.1.2) — the read-only groups attribute (the groups a user belongs to) isn't returned on GET /Users.

Personal access tokens don't honor provisioned-user group permissions

The session correctly resolves a provisioned user's permissions from groups (loadPolicyStatementsForOrganizationif (user.provisionedByOrganizationId) …), but the PAT surfaces in organization-access-tokens.ts all resolve from the base role (membership.assignedRole.role.allPermissions / .resources) with no group branch: createPersonalAccessTokenForViewer, getAvailablePermissionGroupsForMembership, getPermissionsForAccessToken, computeAuthorizationStatements, getGraphQLResolvedResourcePermissionGroupForAccessToken. So a provisioned user (base role Viewer) can't put a group-granted permission on a PAT — it's stripped at creation and again on every use (cache recompute).
Since a provisioned user's PAT can't carry their group-granted permissions, there's no straightforward way to issue a scoped-down token for that user and exercise the group-based permissions end-to-end.

Also, question: Is single-org the intended model for SCIM-provisioned users, or is cross-org membership something you're planning to support?

@mish-elle

Copy link
Copy Markdown
Contributor

To add some context on Aisha's last point, our main use case for multi-org SCIM users is for Platform Operators: the team that manages all organizations on the platform i.e. setting up OIDC, etc. We could work around this by keeping Platform Operators as SSO-only users outside SCIM, but if we're externalizing all user management to SCIM then ideally Platform Operators should be managed through the same automated provisioning/deprovisioning path.

n1ru4l added 20 commits July 16, 2026 15:29
…ganizationand add a flag to enforce login through oidc
…equired" flags via the GraphQL API; implement guard for "oidcForVerifiedDomainsRequired" when another oidc integration attempts to create an user with a domain registered for another organization
…zation.groups" and "Mutation.addGroupMappingToGroup"
… Storage.ensureUserExists. This change should resolve the situation for now and makes the test for auto-updating the oidc provider email pass. I still to refactor that code to be cleaner though
…ions and a disabled user is not able to log in
@n1ru4l
n1ru4l force-pushed the feat-scim-user-group-provisioning branch from 7b0c0d0 to 1db6ac2 Compare July 16, 2026 13:29
@n1ru4l

n1ru4l commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

@mish-elle @iftika1 This PR focuses on provisioning users for organizations, not platform operators (which is out of scope here). It is intentional that all provisioned users are restricted/jailed to the provisioned organization.

@iftika1 I addressed the PATCH operation and totalResult concerns, thanks for reporting these!

I still feel hesitant in including the User.groups attribute as this adds a lot of additional DB reads for list endpoints. Both Okta and Entra work without these. Is this just a concern regarding the correctness of specification implementation or an actual blocker?

Could you succeed testing the integration against your SCIM provider, or were the issues you described (missing User.groups attribute and invalid totalResults) preventing a successful test?

@iftika1

iftika1 commented Jul 16, 2026

Copy link
Copy Markdown

@n1ru4l Appreciate the quick followup. Unfortunately, User.groups is a real requirement for us, not just spec correctness. Our SCIM provider runs a periodic "collect entitlements" reconciliation that reads each user's current group/entitlement set from the User resource itself, so without groups it can't reconcile what a user holds.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants