Commit 93fd43b
feat(scim): SCIM 2.0 directory provisioning with group-to-access projection
Adds a SCIM 2.0 service provider so an organization's identity provider
(Okta, Microsoft Entra ID, OneLogin, JumpCloud) can create, update,
deactivate, and remove members, and map pushed groups onto permission
groups, workspace access, and the organization admin role.
Protocol surface (`/api/scim/v2`)
- Users and Groups: list with `eq`/`and` filters and paging, get, create,
replace, patch, delete; discovery documents for ServiceProviderConfig,
ResourceTypes, and Schemas.
- A dedicated `defineScimRoute` builder: bearer authentication to a new
`scim_connection` principal, per-connection rate limit, RFC 7644 error
envelope, `application/scim+json`, 415 on wrong media type.
- Tolerances for what providers actually send: Entra's capitalized ops and
string booleans, one-element arrays, path-less dotted-key replaces, and
filtered email paths that create their target; Okta's path-less
`replace {active:false}` and filtered member removal.
Identity and safety
- Never links by unverified email: resolution is tombstone by externalId,
then verified-domain email within this organization, then create.
- Every create and email change is refused outside the organization's
verified domains, closing the SCIM account-takeover shape.
- Deactivation is a new reversible `user.suspendedAt` state, enforced at
session creation and both API-key auth paths. It is deliberately not
`banned`, which archives owned workspaces and cannot be undone.
- The organization owner cannot be deprovisioned; seats are validated with
the same policy as SSO admission.
Projection
- Every grant SCIM makes is recorded, so withdrawing group access touches
only what the directory granted and never a manual grant.
- Permission groups gain `membershipMode: 'explicit'` so a directory-managed
group governs nobody when empty instead of widening to everyone.
- An hourly reconcile sweep re-applies mappings idempotently.
Shared primitives extracted from routes so UI and SCIM share one
implementation: per-user session revocation (with security-version bump),
personal API-key revocation, suspend/unsuspend, member role change,
workspace access grant/revoke, permission-group add/remove member. The
member role route now uses the role-change primitive under the org lock.
Admin surface under `/api/organizations/[id]/scim`: connection settings,
credential issue/revoke (two active for rotation, digest-only storage),
group mappings, activity log, on-demand reconcile.
Migration 0323 is expand-only: nine new tables plus nullable/defaulted
columns on `user` and `permission_group`.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JVf3fLVj7iWzED7L2wQvhG1 parent 776f148 commit 93fd43b
98 files changed
Lines changed: 32321 additions & 72 deletions
File tree
- apps
- docs
- content/docs/platform/enterprise
- sim
- app/api
- cron/scim-reconcile
- files/uploads
- organizations/[id]
- members/[memberId]
- scim
- activity
- credentials
- [credentialId]
- mappings
- [mappingId]
- reconcile
- scim/v2
- Groups
- [id]
- ResourceTypes
- [id]
- Schemas
- [id]
- ServiceProviderConfig
- Users
- [id]
- lib
- api-key
- api
- contracts
- server/routes
- auth
- compare/data
- core
- application
- config
- execution/sandbox/bundles
- invitations
- organizations/members
- permission-groups
- application
- posthog
- scim
- application
- admin
- groups
- users
- identity
- projection
- protocol
- reconcile
- repository
- uploads/upload-session
- workflows/application
- workspaces/access
- docker
- helm/sim
- packages
- audit/src
- auth/src
- db
- migrations
- meta
- testing/src/mocks
- scripts
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| 7 | + | |
7 | 8 | | |
8 | 9 | | |
9 | 10 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
278 | 278 | | |
279 | 279 | | |
280 | 280 | | |
281 | | - | |
| 281 | + | |
282 | 282 | | |
283 | 283 | | |
284 | 284 | | |
| |||
305 | 305 | | |
306 | 306 | | |
307 | 307 | | |
308 | | - | |
| 308 | + | |
309 | 309 | | |
310 | 310 | | |
311 | 311 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
453 | 453 | | |
454 | 454 | | |
455 | 455 | | |
456 | | - | |
| 456 | + | |
457 | 457 | | |
458 | 458 | | |
459 | 459 | | |
| |||
0 commit comments