Skip to content

feat(plugin-auth): env-side SCIM 2.0 via @better-auth/scim (ADR-0071, OPEN mechanism)#2356

Merged
xuyushun441-sys merged 4 commits into
mainfrom
feat/scim-plugin
Jun 27, 2026
Merged

feat(plugin-auth): env-side SCIM 2.0 via @better-auth/scim (ADR-0071, OPEN mechanism)#2356
xuyushun441-sys merged 4 commits into
mainfrom
feat/scim-plugin

Conversation

@xuyushun441-sys

Copy link
Copy Markdown
Contributor

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)

  • Install @better-auth/scim (MIT); push scim({ storeSCIMToken: 'hashed' }) under OS_SCIM_ENABLED; force the admin plugin on (active:false → ban needs it).
  • New sys_scim_provider object + registration in plugin-auth's authIdentityObjects manifest (export ≠ provisioning — the manifest drives schema sync, D7).
  • Map scimProvider → sys_scim_provider in AUTH_MODEL_TO_PROTOCOL; the adapter auto-bridges camelCase↔snake_case. Fixed the now-stale adapter TODO comment.
  • Source-marking fix: SCIM creates sys_account bypassing better-auth's account.create.after, so users landed source=env_native. Added an ObjectQL afterInsert hook on sys_account that stamps source=idp_provisioned for non-credential accounts (robust to the creation path; uses the QueryAST where key — filter is silently ignored).
  • Token stored hashed, never cleartext.

Verified E2E on the objectos-ee rig

generate-token ✅ · POST /Users201 ✅ · PATCH active:false204 + sys_user.banned=1 ✅ (compliance offboarding) · GET /Users ✅ · SCIM user → source=idp_provisioned ✅ · dev admin (credential) stays env_native ✅. Full plugin-auth suite: 137 passed, incl. new SCIM wiring tests.

🤖 Generated with Claude Code

os-zhuang and others added 4 commits June 27, 2026 14:57
…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>
@vercel

vercel Bot commented Jun 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jun 27, 2026 7:55am

Request Review

@github-actions github-actions Bot added dependencies Pull requests that update a dependency file tests size/m labels Jun 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/platform-objects, @objectstack/plugin-auth.

11 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/implementation-status.mdx (via @objectstack/plugin-auth)
  • content/docs/concepts/packages.mdx (via @objectstack/platform-objects, @objectstack/plugin-auth)
  • content/docs/concepts/setup-app.mdx (via @objectstack/platform-objects)
  • content/docs/getting-started/cli.mdx (via @objectstack/plugin-auth)
  • content/docs/guides/auth-sso.mdx (via @objectstack/plugin-auth)
  • content/docs/guides/authentication.mdx (via @objectstack/plugin-auth)
  • content/docs/guides/kernel-services.mdx (via @objectstack/plugin-auth)
  • content/docs/guides/packages.mdx (via @objectstack/platform-objects, @objectstack/plugin-auth)
  • content/docs/guides/plugins.mdx (via @objectstack/plugin-auth)
  • content/docs/guides/production-readiness.mdx (via @objectstack/plugin-auth)
  • content/docs/releases/v9.mdx (via @objectstack/plugin-auth)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@xuyushun441-sys xuyushun441-sys merged commit 911c7aa into main Jun 27, 2026
17 checks passed
@xuyushun441-sys xuyushun441-sys deleted the feat/scim-plugin branch June 27, 2026 08:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file size/m tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants