feat(plugin-auth): env-side SCIM 2.0 via @better-auth/scim (ADR-0071, OPEN mechanism)#2356
Merged
Conversation
…ice Provider (ADR-0071)
Adds the OPEN SCIM mechanism so an external IdP (Okta/Entra) can auto-
provision/deprovision this environment's users. Mirrors the @better-auth/sso
wiring:
- add @better-auth/scim dep; push scim({storeSCIMToken:'hashed'}) under
OS_SCIM_ENABLED; force the admin plugin on (active:false -> ban needs it)
- map scimProvider -> sys_scim_provider in AUTH_MODEL_TO_PROTOCOL (the adapter
auto-bridges camelCase->snake_case); fix the now-stale adapter TODO comment
- new sys_scim_provider object (token stored hashed, read-only over data API)
- AUTH_SCIM_PROVIDER_SCHEMA field map; export SysScimProvider
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Exporting the object from platform-objects/identity is necessary but not sufficient — schema provisioning is driven by plugin-auth's explicit authIdentityObjects list (the D7 compile-time + runtime registration). Without this the table was never created and @better-auth/scim's generate-token 500'd on `no such table: sys_scim_provider`. Verified E2E: token gen, provision (201), deprovision (active:false -> banned), list — all green on the objectos-ee rig. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…sers
@better-auth/scim creates sys_account bypassing better-auth's
databaseHooks.account.create.after, so stampIdentitySource never fired and
SCIM users landed source=env_native instead of idp_provisioned (ADR-0024 D4).
Fix: register an ObjectQL afterInsert hook on sys_account at kernel:ready that
stamps idp_provisioned for any non-credential account whose user has no local
credential — robust to the creation path (catches SCIM and OAuth alike),
idempotent, and never breaks the insert. Uses ctx.getService('objectql') (the
auth manager's getDataEngine() is not wired at kernel:ready) and the QueryAST
`where` key (not `filter` — a wrong key is silently ignored and counts every
row, the latent bug also present in stampIdentitySource's federated branch).
Verified E2E on the objectos-ee rig: SCIM-provisioned user -> idp_provisioned;
local dev admin (credential) stays env_native.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…; OS_SCIM_ENABLED forces scim + admin) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 2 package(s): 11 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The OPEN per-environment SCIM mechanism for Enterprise Identity (design: cloud ADR-0071 / cloud#611, implementing the SCIM slice ADR-0024 D6 deferred). The environment becomes a SCIM 2.0 Service Provider so an external IdP (Okta / Entra) can auto-provision / deprovision its users. Off by default (
OS_SCIM_ENABLED); the paid entitlement gate + token-admin UI land cloud-side, separately.What's here (mirrors the @better-auth/sso wiring)
@better-auth/scim(MIT); pushscim({ storeSCIMToken: 'hashed' })underOS_SCIM_ENABLED; force theadminplugin on (active:false→ ban needs it).sys_scim_providerobject + registration inplugin-auth'sauthIdentityObjectsmanifest (export ≠ provisioning — the manifest drives schema sync, D7).scimProvider → sys_scim_providerinAUTH_MODEL_TO_PROTOCOL; the adapter auto-bridges camelCase↔snake_case. Fixed the now-stale adapter TODO comment.sys_accountbypassing better-auth'saccount.create.after, so users landedsource=env_native. Added an ObjectQLafterInserthook onsys_accountthat stampssource=idp_provisionedfor non-credential accounts (robust to the creation path; uses the QueryASTwherekey —filteris silently ignored).Verified E2E on the objectos-ee rig
generate-token✅ ·POST /Users→ 201 ✅ ·PATCH active:false→ 204 + sys_user.banned=1 ✅ (compliance offboarding) ·GET /Users✅ · SCIM user → source=idp_provisioned ✅ · dev admin (credential) stays env_native ✅. Fullplugin-authsuite: 137 passed, incl. new SCIM wiring tests.🤖 Generated with Claude Code