Skip to content

Commit ee34d86

Browse files
committed
feat: enhance OIDC endpoint origin fetching to directly inject discovered origins into trusted-origins list
1 parent 9c355ab commit ee34d86

1 file changed

Lines changed: 30 additions & 23 deletions

File tree

server/utils/auth.ts

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,29 @@ type Auth = ReturnType<typeof betterAuth>;
1111
let _auth: Auth | undefined;
1212

1313
/**
14-
* Runtime cache of OIDC endpoint origins discovered from IdP discovery documents.
14+
* Fetch an OIDC discovery document and inject every endpoint origin into
15+
* better-auth's live trusted-origins list so the SSO plugin trusts them
16+
* during provider registration.
1517
*
16-
* Populated by `prefetchOidcEndpointOrigins()` before provider registration so
17-
* that better-auth's trusted-origins check passes for IdPs whose token/userinfo
18-
* endpoints live on a different domain than the issuer (e.g. Google).
19-
*/
20-
const discoveredIdpOrigins = new Set<string>();
21-
22-
/**
23-
* Fetch an OIDC discovery document and cache every endpoint origin so
24-
* better-auth trusts them during provider registration.
18+
* Why: better-auth resolves `trustedOrigins` once at init and caches the
19+
* result as a plain array. The SSO plugin then validates every URL in the
20+
* discovery document (discovery endpoint, token_endpoint, jwks_uri, etc.)
21+
* against that cached array. IdPs like Google use multiple domains
22+
* (accounts.google.com vs oauth2.googleapis.com), so we must discover
23+
* those origins and inject them into the live array before registration.
2524
*
26-
* Must be called **before** `auth.api.registerSSOProvider()` so the
27-
* origins are available when better-auth validates discovery endpoints.
25+
* Must be called **before** `auth.api.registerSSOProvider()`.
2826
*/
2927
export async function prefetchOidcEndpointOrigins(issuerUrl: string): Promise<void> {
3028
const discoveryUrl = issuerUrl.replace(/\/+$/, "") + "/.well-known/openid-configuration";
3129
const res = await $fetch<Record<string, unknown>>(discoveryUrl, {
3230
timeout: 10_000,
3331
});
3432

35-
// Extract origins from all *_endpoint fields in the discovery document
33+
// Collect origins from all endpoint fields + the issuer itself
34+
const newOrigins = new Set<string>();
35+
try { newOrigins.add(new URL(issuerUrl).origin); } catch {}
36+
3637
const endpointKeys = [
3738
"authorization_endpoint",
3839
"token_endpoint",
@@ -45,11 +46,17 @@ export async function prefetchOidcEndpointOrigins(issuerUrl: string): Promise<vo
4546
for (const key of endpointKeys) {
4647
const value = res[key];
4748
if (typeof value === "string") {
48-
try {
49-
discoveredIdpOrigins.add(new URL(value).origin);
50-
} catch {
51-
// Skip malformed URLs
52-
}
49+
try { newOrigins.add(new URL(value).origin); } catch {}
50+
}
51+
}
52+
53+
// Push directly into better-auth's live trustedOrigins array so
54+
// isTrustedOrigin() sees them immediately (it reads this.trustedOrigins).
55+
const ctx = await (auth as any).$context;
56+
const existing = new Set(ctx.trustedOrigins as string[]);
57+
for (const origin of newOrigins) {
58+
if (!existing.has(origin)) {
59+
(ctx.trustedOrigins as string[]).push(origin);
5360
}
5461
}
5562
}
@@ -59,11 +66,11 @@ export async function prefetchOidcEndpointOrigins(issuerUrl: string): Promise<vo
5966
*
6067
* Combines:
6168
* 1. App origins (base URL, configured origins, dev defaults)
62-
* 2. Origins auto-discovered from OIDC discovery documents
63-
* 3. Already-registered SSO provider issuers from the database
69+
* 2. Already-registered SSO provider issuers from the database
6470
*
65-
* For IdPs that cannot be auto-discovered, add their origin to the
66-
* BETTER_AUTH_TRUSTED_ORIGINS environment variable.
71+
* Additional IdP endpoint origins are injected at runtime by
72+
* `prefetchOidcEndpointOrigins()` directly into the auth context.
73+
* For edge cases, add origins to the BETTER_AUTH_TRUSTED_ORIGINS env var.
6774
*/
6875
function resolveTrustedOrigins(baseUrl: string): (request?: Request) => Promise<string[]> {
6976
const configuredOrigins = env.BETTER_AUTH_TRUSTED_ORIGINS;
@@ -89,7 +96,7 @@ function resolveTrustedOrigins(baseUrl: string): (request?: Request) => Promise<
8996
);
9097

9198
return async () => {
92-
const allOrigins = [...staticOrigins, ...discoveredIdpOrigins];
99+
const allOrigins = [...staticOrigins];
93100

94101
// Load already-registered SSO provider issuers from the database
95102
try {

0 commit comments

Comments
 (0)