[GH-ISSUE #8811] feat: Allow overriding OAuth endpoint URLs for social providers (emulator support) #28521

Open
opened 2026-04-17 19:58:29 -05:00 by GiteaMirror · 1 comment
Owner

Originally created by @designorant on GitHub (Mar 28, 2026).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/8811

Originally assigned to: @GautamBytes on GitHub.

Problem

Social providers like Google have their OAuth endpoints (authorization, token, userinfo, JWKS) hardcoded in the provider implementations. For example, in google.ts:

authorizationEndpoint: "https://accounts.google.com/o/oauth2/v2/auth"
tokenEndpoint: "https://oauth2.googleapis.com/token"
// JWKS: "https://www.googleapis.com/oauth2/v3/certs"

This makes it impossible to use local OAuth emulators for development and testing. Tools like vercel-labs/emulate provide full OAuth 2.0 / OIDC emulation with user pickers, token exchange, and JWKS — but Better Auth can't point at them because the endpoints are hardcoded.

Proposed Solution

Allow optional endpoint overrides in the social provider config:

socialProviders: {
  google: {
    clientId: process.env.GOOGLE_CLIENT_ID,
    clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    // Optional: override endpoints for local dev / emulators
    authorizationEndpoint: process.env.GOOGLE_EMULATOR_URL 
      ? `${process.env.GOOGLE_EMULATOR_URL}/o/oauth2/v2/auth` 
      : undefined,
    tokenEndpoint: process.env.GOOGLE_EMULATOR_URL
      ? `${process.env.GOOGLE_EMULATOR_URL}/oauth2/token`
      : undefined,
    // Falls back to hardcoded production URLs when undefined
  },
},

When the override is undefined, the current hardcoded URLs are used — zero breaking changes.

Prior Art

NextAuth.js / Auth.js already supports this pattern:

import Google from '@auth/core/providers/google'

Google({
  clientId: process.env.GOOGLE_CLIENT_ID,
  clientSecret: process.env.GOOGLE_CLIENT_SECRET,
  authorization: {
    url: `${process.env.GOOGLE_EMULATOR_URL}/o/oauth2/v2/auth`,
    params: { scope: 'openid email profile' },
  },
  token: { url: `${process.env.GOOGLE_EMULATOR_URL}/oauth2/token` },
  userinfo: { url: `${process.env.GOOGLE_EMULATOR_URL}/oauth2/v2/userinfo` },
})

This enables full OAuth flow testing locally with emulators like vercel-labs/emulate, which provide user pickers, OIDC discovery, token exchange, and JWKS endpoints on localhost.

Impact

This would benefit all social providers (Google, GitHub, Apple, etc.), not just Google. The change is minimal — each provider's createAuthorizationURL and validateAuthorizationCode calls already receive options, so the endpoints could be read from options with a fallback to the current hardcoded values.

Originally created by @designorant on GitHub (Mar 28, 2026). Original GitHub issue: https://github.com/better-auth/better-auth/issues/8811 Originally assigned to: @GautamBytes on GitHub. ## Problem Social providers like Google have their OAuth endpoints (authorization, token, userinfo, JWKS) hardcoded in the provider implementations. For example, in `google.ts`: ```ts authorizationEndpoint: "https://accounts.google.com/o/oauth2/v2/auth" tokenEndpoint: "https://oauth2.googleapis.com/token" // JWKS: "https://www.googleapis.com/oauth2/v3/certs" ``` This makes it impossible to use local OAuth emulators for development and testing. Tools like [`vercel-labs/emulate`](https://github.com/vercel-labs/emulate) provide full OAuth 2.0 / OIDC emulation with user pickers, token exchange, and JWKS — but Better Auth can't point at them because the endpoints are hardcoded. ## Proposed Solution Allow optional endpoint overrides in the social provider config: ```ts socialProviders: { google: { clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, // Optional: override endpoints for local dev / emulators authorizationEndpoint: process.env.GOOGLE_EMULATOR_URL ? `${process.env.GOOGLE_EMULATOR_URL}/o/oauth2/v2/auth` : undefined, tokenEndpoint: process.env.GOOGLE_EMULATOR_URL ? `${process.env.GOOGLE_EMULATOR_URL}/oauth2/token` : undefined, // Falls back to hardcoded production URLs when undefined }, }, ``` When the override is `undefined`, the current hardcoded URLs are used — zero breaking changes. ## Prior Art NextAuth.js / Auth.js already supports this pattern: ```ts import Google from '@auth/core/providers/google' Google({ clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, authorization: { url: `${process.env.GOOGLE_EMULATOR_URL}/o/oauth2/v2/auth`, params: { scope: 'openid email profile' }, }, token: { url: `${process.env.GOOGLE_EMULATOR_URL}/oauth2/token` }, userinfo: { url: `${process.env.GOOGLE_EMULATOR_URL}/oauth2/v2/userinfo` }, }) ``` This enables full OAuth flow testing locally with emulators like [`vercel-labs/emulate`](https://github.com/vercel-labs/emulate), which provide user pickers, OIDC discovery, token exchange, and JWKS endpoints on localhost. ## Impact This would benefit all social providers (Google, GitHub, Apple, etc.), not just Google. The change is minimal — each provider's `createAuthorizationURL` and `validateAuthorizationCode` calls already receive `options`, so the endpoints could be read from `options` with a fallback to the current hardcoded values.
GiteaMirror added the enhancementoauth labels 2026-04-17 19:58:29 -05:00
Author
Owner

@GautamBytes commented on GitHub (Mar 28, 2026):

Looking into it!

<!-- gh-comment-id:4148228615 --> @GautamBytes commented on GitHub (Mar 28, 2026): Looking into it!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#28521