Observed 2026-08-19 while implementing #9653 (the four /admin/sso/* bridges now gate on the shared ADR-0068 platform-admin judge before delegating). Filed unassigned, finding — this records a posture divergence between two surfaces that reach the same operation; whether to align them is a policy decision.
What the two surfaces now answer
POST /api/v1/auth/sso/register (better-auth's own endpoint, served by the catch-all) is guarded by the ADR-0024 before-hook in auth-manager.ts (ctx.path === '/sso/register'), whose admit set is platform admin OR org owner/admin of the caller's active org (isOrgOrPlatformAdmin). That hook was deliberate when it landed: better-auth's own model treats org-scoped SSO providers as org-admin-manageable.
POST /api/v1/auth/admin/sso/{register,register-saml} (the ObjectStack bridges the sys_sso_provider actions call) now gate on platform admin only (judgePlatformAdmin), per #9653's triage adjudication: ADR-0068 D4 — "platform-operator actions gate on isPlatformAdmin (sole operator)", and registering an identity provider is a platform-operator action.
So after #9653 an org owner/admin who is not a platform admin is refused 403 PERMISSION_DENIED at the bridge, while the direct endpoint still admits them for the same underlying registration. The bridge tightening is therefore not a boundary for that caller class — it is honest labelling on the surface the console uses, with the vendor-native surface still carrying the wider ADR-0024 admit set.
Why it is worth recording rather than fixing in #9653
Related context: #9653 (the bridge gate + the measured vendor posture on the installed @better-auth/sso 1.7.1), ADR-0024 (open SSO mechanism), ADR-0068 D4 (platform-operator actions).
Observed 2026-08-19 while implementing #9653 (the four
/admin/sso/*bridges now gate on the shared ADR-0068 platform-admin judge before delegating). Filed unassigned,finding— this records a posture divergence between two surfaces that reach the same operation; whether to align them is a policy decision.What the two surfaces now answer
POST /api/v1/auth/sso/register(better-auth's own endpoint, served by the catch-all) is guarded by the ADR-0024 before-hook inauth-manager.ts(ctx.path === '/sso/register'), whose admit set is platform admin OR org owner/admin of the caller's active org (isOrgOrPlatformAdmin). That hook was deliberate when it landed: better-auth's own model treats org-scoped SSO providers as org-admin-manageable.POST /api/v1/auth/admin/sso/{register,register-saml}(the ObjectStack bridges thesys_sso_provideractions call) now gate on platform admin only (judgePlatformAdmin), per #9653's triage adjudication: ADR-0068 D4 — "platform-operator actions gate onisPlatformAdmin(sole operator)", and registering an identity provider is a platform-operator action.So after #9653 an org owner/admin who is not a platform admin is refused
403 PERMISSION_DENIEDat the bridge, while the direct endpoint still admits them for the same underlying registration. The bridge tightening is therefore not a boundary for that caller class — it is honest labelling on the surface the console uses, with the vendor-native surface still carrying the wider ADR-0024 admit set.Why it is worth recording rather than fixing in #9653
auth-manager.ts) with its own history and its own rationale (org-scoped providers are org-admin-manageable by the vendor's design; the hook's comment block says why it exists).Related context: #9653 (the bridge gate + the measured vendor posture on the installed
@better-auth/sso1.7.1), ADR-0024 (open SSO mechanism), ADR-0068 D4 (platform-operator actions).