Skip to content

fix(auth): trust public-routable external-IdP origins at SSO registration (ADR-0024 / cloud#551) - #2370

Merged
os-zhuang merged 1 commit into
mainfrom
adr-0024-sso-public-idp-trust
Jun 27, 2026
Merged

os-zhuang merged 1 commit into
mainfrom
adr-0024-sso-public-idp-trust

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Why

Follow-up to #2363 (the cloud#551 SSO admin-gate). Local E2E surfaced a second gap: @better-auth/sso's discovery validation (validateDiscoveryUrl + normalizeAndValidateUrl) requires every IdP endpoint origin to be in trustedOrigins — even for a publicly-routable IdP. So registering any external OIDC IdP returns 400 discovery_untrusted_origin unless the operator pre-listed it, which breaks ADR-0024's "register your IdP at runtime, no boot config" promise.

What

When the external-SSO RP is enabled (isSsoWired()), trustedOrigins is now a per-request function that, for a POST /sso/register | /sso/update-provider, additionally trusts the public-routable issuer / oidcConfig endpoint origins declared in the request body — using @better-auth/core's own isPublicRoutableHost (the same predicate better-auth's sub-endpoint check uses). All other requests get exactly the previous static origins.

Safety:

  • Private / internal / loopback hosts are never auto-trusted — they still require explicit trustedOrigins config (the documented SSRF escape hatch).
  • better-auth's own DNS-resolution checks still apply.
  • The function is only consulted for the two SSO admin paths; normal CSRF/origin behavior is unchanged.

Verification (browser E2E, local prod-like stack, no trustedOrigins entry)

  • Same-origin public IdP GitLab.com (issuer + all discovered endpoints on one origin — like Okta / Entra / Auth0 / Keycloak) → register 200, oidcConfig hydrated from GitLab's live discovery (was a hard 400).
  • Google's main discovery URL now passes too; Google still needs its split googleapis.com endpoint origins trusted (documented caveat — multi-domain IdPs).
  • Regression: a non-admin registering a valid public IdP is still 403 (the fix(auth): admin-gate self-service SSO provider registration + default-role JIT (ADR-0024 / cloud#551) #2363 admin gate fires before discovery); normal auth flows intact.

Scope

Only packages/plugins/plugin-auth/src/auth-manager.ts (+ changeset). SSO mechanism stays framework-open.

🤖 Generated with Claude Code

…tion (ADR-0024 / cloud#551)

@better-auth/sso's discovery validation requires every IdP endpoint origin to
be in trustedOrigins — even for a publicly-routable IdP — so registering any
external IdP returned 400 discovery_untrusted_origin unless pre-listed in boot
config, breaking ADR-0024's runtime self-service promise.

When the SSO RP is enabled, expose trustedOrigins as a per-request function
that, for POST /sso/register|/sso/update-provider, additionally trusts the
PUBLIC-ROUTABLE issuer/oidcConfig endpoint origins from the request body
(@better-auth/core isPublicRoutableHost). Private/internal/loopback hosts are
never auto-trusted; better-auth's DNS-resolution checks still apply.

Verified E2E: a same-origin public IdP (GitLab.com) now registers at runtime
with no boot config (was 400); the admin gate still fires before discovery.

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 1:43pm

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tooling size/s labels Jun 27, 2026
@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.

@os-zhuang
os-zhuang merged commit caa3ef4 into main Jun 27, 2026
16 checks passed
@os-zhuang
os-zhuang deleted the adr-0024-sso-public-idp-trust branch June 27, 2026 13:44

This branch was successfully deployed

1 active deployment
Preview — eae98b3d Deployed Jun 27, 2026 by vercel[bot]
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/s tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant