Skip to content

fix(auth): admin-gate self-service SSO provider registration + default-role JIT (ADR-0024 / cloud#551)#2363

Merged
os-zhuang merged 2 commits into
mainfrom
adr-0024-sso-admin-gate
Jun 27, 2026
Merged

fix(auth): admin-gate self-service SSO provider registration + default-role JIT (ADR-0024 / cloud#551)#2363
os-zhuang merged 2 commits into
mainfrom
adr-0024-sso-admin-gate

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Why

Part of the cloud#551 Unified Identity V1 (ADR-0024) E2E. Local browser testing surfaced a real gap that static review had missed.

@better-auth/sso's POST /sso/register only enforces org-admin when body.organizationId is supplied (index.mjs: if (ctx.body.organizationId) { … hasOrgAdminRole … }). A global (org-less) provider passes on nothing but a valid session — so any authenticated env member can register an env-wide external IdP, a JIT-provisioning / login-routing vector. This violates ADR-0024's "registerSSOProvider is admin-only".

What

  • A3 — admin gate: a before-hook on /sso/register requiring the caller to be a platform admin OR an owner/admin of their active org, regardless of whether organizationId is passed. Fail-closed; unauthenticated requests still fall through to sessionMiddleware (→ 401). New helpers resolveActor() (hook-order-independent cookie/bearer resolution) and isOrgOrPlatformAdmin() (mirrors customSession's role derivation; reads via withSystemReadContext).
  • A4 — default role: pass organizationProvisioning.defaultRole:'member' to sso() so a first-time federated login lands with an explicit role (over SecurityPlugin's member_default baseline).

Verification (browser E2E, local prod-like stack + a mock OIDC IdP)

  • Non-admin member register → 403 SSO_REGISTER_FORBIDDEN (was 200 before this change).
  • Org owner register → 200 (discovery hydrated).
  • External-IdP OIDC login → JIT user created; better-auth list-accounts shows providerId set = the sys_account source marker.
  • Role-less federated user reaches a usable env (member_default); anon denied.
  • tsc adds no new errors (the two pre-existing DTS errors — @better-auth/scim @1241 and passwordRejectBreached @865 — are from prior commits, not this one).

Scope

Only packages/plugins/plugin-auth/src/auth-manager.ts. The SSO mechanism stays framework-open (no identity-governance added). Closes the A-workstream gap for cloud#551.

🤖 Generated with Claude Code

…t-role JIT (ADR-0024)

@better-auth/sso's POST /sso/register only enforces org-admin when
`body.organizationId` is supplied — a GLOBAL (org-less) provider passes
on nothing but a valid session. So any authenticated env member could
register an env-wide external IdP (a JIT-provisioning / login-routing
vector), violating ADR-0024's "registerSSOProvider is admin-only".

Add a before-hook gate on /sso/register requiring the caller to be a
platform admin OR an owner/admin of their active org, regardless of
whether organizationId is passed. Fail-closed; unauthenticated requests
still fall through to sessionMiddleware's 401. New helpers resolveActor()
(hook-order-independent cookie/bearer resolution) and isOrgOrPlatformAdmin()
(mirrors customSession's role derivation, reads via withSystemReadContext).

Also pass `organizationProvisioning.defaultRole:'member'` to sso() so a
first-time federated login lands with an explicit default role (over the
SecurityPlugin member_default baseline).

Verified E2E on the local prod-like stack against a mock OIDC IdP:
non-admin register → 403 SSO_REGISTER_FORBIDDEN; owner → 200; external-IdP
login JIT-provisions the user with sys_account.provider_id set.

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 12:52pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/plugin-auth.

10 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/plugin-auth)
  • 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/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.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions github-actions Bot added documentation Improvements or additions to documentation tooling labels Jun 27, 2026
@os-zhuang
os-zhuang merged commit 22b32c1 into main Jun 27, 2026
16 checks passed
@os-zhuang
os-zhuang deleted the adr-0024-sso-admin-gate branch June 27, 2026 12:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant