You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* fix(auth): admin-gate self-service SSO provider registration + default-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>
* chore: add changeset for SSO register admin-gate
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
`@better-auth/sso`'s `POST /sso/register` only enforces org-admin when `body.organizationId` is supplied — a **global** (org-less) provider passed on nothing but a valid session, so any authenticated env member could register an env-wide external IdP (a JIT-provisioning / login-routing vector). This closed the "registerSSOProvider is admin-only" requirement of ADR-0024's first slice.
8
+
9
+
-**plugin-auth**: a `before`-hook on `/sso/register` now requires the caller to be a platform admin OR an owner/admin of their active org, regardless of `organizationId`. 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`).
10
+
-**plugin-auth**: `sso()` now receives `organizationProvisioning.defaultRole:'member'` so a first-time federated login lands with an explicit role (over SecurityPlugin's `member_default` baseline).
11
+
12
+
Additive and fail-closed — no behavior change for legitimate admins. The SSO mechanism stays framework-open (no identity-governance added).
0 commit comments