From 2c29c1e91929def02b02456dc001b4e9f5f049fd Mon Sep 17 00:00:00 2001 From: Gustavo Valverde Date: Thu, 28 May 2026 15:01:30 +0100 Subject: [PATCH] fix(oauth)!: derive redirect URI from per-request baseURL via declarative callbackPath Multi-host deployments configured with `baseURL: { allowedHosts: [...] }` now produce absolute `redirect_uri` values for generic-OAuth providers. Auth0 and other strict authorization servers previously rejected the authorize step because `genericOAuth` captured `ctx.baseURL` at init time, which is the empty sentinel under dynamic config. Every `OAuthProvider` now declares `callbackPath: string`. Endpoints compose `redirectURI = ctx.context.baseURL + provider.callbackPath` in the social-sign-in, callback, link-account, and oauth-proxy handlers, removing the init-time `ctx.baseURL` read across the OAuth surface. Built-in providers use `/callback/`; generic-OAuth uses `/oauth2/callback/`. The interface change is invisible to app developers. Third-party plugin authors who construct their own `OAuthProvider` must add `callbackPath` to their factory. Resolves #9593. Partial fix for #4151. Co-Authored-By: thaoms <2323270+thaoms@users.noreply.github.com> --- .changeset/oauth-callback-path-declarative.md | 22 ++++ .../better-auth/src/api/routes/account.ts | 2 +- .../better-auth/src/api/routes/callback.ts | 2 +- .../better-auth/src/api/routes/sign-in.ts | 2 +- .../generic-oauth/generic-oauth.test.ts | 121 ++++++++++++++++++ .../src/plugins/generic-oauth/index.ts | 1 + .../src/plugins/oauth-proxy/index.ts | 2 +- packages/core/src/oauth2/oauth-provider.ts | 11 ++ packages/core/src/social-providers/apple.ts | 1 + .../core/src/social-providers/atlassian.ts | 1 + packages/core/src/social-providers/cognito.ts | 1 + packages/core/src/social-providers/discord.ts | 1 + packages/core/src/social-providers/dropbox.ts | 1 + .../core/src/social-providers/facebook.ts | 1 + packages/core/src/social-providers/figma.ts | 1 + packages/core/src/social-providers/github.ts | 1 + packages/core/src/social-providers/gitlab.ts | 1 + packages/core/src/social-providers/google.ts | 1 + .../core/src/social-providers/huggingface.ts | 1 + packages/core/src/social-providers/kakao.ts | 1 + packages/core/src/social-providers/kick.ts | 1 + packages/core/src/social-providers/line.ts | 1 + packages/core/src/social-providers/linear.ts | 1 + .../core/src/social-providers/linkedin.ts | 1 + .../social-providers/microsoft-entra-id.ts | 1 + packages/core/src/social-providers/naver.ts | 1 + packages/core/src/social-providers/notion.ts | 1 + packages/core/src/social-providers/paybin.ts | 1 + packages/core/src/social-providers/paypal.ts | 1 + packages/core/src/social-providers/polar.ts | 1 + packages/core/src/social-providers/railway.ts | 1 + packages/core/src/social-providers/reddit.ts | 1 + packages/core/src/social-providers/roblox.ts | 1 + .../core/src/social-providers/salesforce.ts | 1 + packages/core/src/social-providers/slack.ts | 1 + packages/core/src/social-providers/spotify.ts | 1 + packages/core/src/social-providers/tiktok.ts | 1 + packages/core/src/social-providers/twitch.ts | 1 + packages/core/src/social-providers/twitter.ts | 1 + packages/core/src/social-providers/vercel.ts | 1 + packages/core/src/social-providers/vk.ts | 1 + packages/core/src/social-providers/wechat.ts | 1 + packages/core/src/social-providers/zoom.ts | 1 + 43 files changed, 194 insertions(+), 4 deletions(-) create mode 100644 .changeset/oauth-callback-path-declarative.md diff --git a/.changeset/oauth-callback-path-declarative.md b/.changeset/oauth-callback-path-declarative.md new file mode 100644 index 0000000000..afb524c0e4 --- /dev/null +++ b/.changeset/oauth-callback-path-declarative.md @@ -0,0 +1,22 @@ +--- +"better-auth": minor +"@better-auth/core": minor +--- + +Derive OAuth `redirect_uri` from the per-request `baseURL` so social and generic-OAuth sign-in work end-to-end under `baseURL: { allowedHosts: [...] }`. + +Before this change, the `genericOAuth` plugin captured `ctx.baseURL` at init time and sent providers a relative URI like `/oauth2/callback/` whenever a dynamic baseURL was configured. Auth0 and other strict providers rejected the authorize request. Built-in social providers were unaffected because their endpoints already resolved per-request. + +The fix is structural rather than a string patch. Every `OAuthProvider` now declares a `callbackPath: string` that describes its callback path under the per-request `baseURL`. The framework composes `redirectURI = ctx.context.baseURL + provider.callbackPath` inside the sign-in, callback, link-account, and oauth-proxy endpoints. The init-time `ctx.baseURL` is no longer read by any OAuth provider, which removes the bug class. + +Resolves #9593. Partial fix for #4151 — `redirect_uri` composition now respects `allowedHosts` for both built-in providers and generic-OAuth providers. + +BREAKING CHANGE: Custom `OAuthProvider` implementations must declare `callbackPath`. End-user `betterAuth({...})` config is unaffected; only authors of custom OAuth provider plugins need to update their factories. Convention: + +```ts +// built-in lane +callbackPath: `/callback/`, + +// generic-oauth lane +callbackPath: `/oauth2/callback/`, +``` diff --git a/packages/better-auth/src/api/routes/account.ts b/packages/better-auth/src/api/routes/account.ts index e26224d0e4..4c409d2b83 100644 --- a/packages/better-auth/src/api/routes/account.ts +++ b/packages/better-auth/src/api/routes/account.ts @@ -378,7 +378,7 @@ export const linkSocialAccount = createAuthEndpoint( const url = await provider.createAuthorizationURL({ state: state.state, codeVerifier: state.codeVerifier, - redirectURI: `${c.context.baseURL}/callback/${provider.id}`, + redirectURI: `${c.context.baseURL}${provider.callbackPath}`, scopes: c.body.scopes, loginHint: c.body.loginHint, additionalParams: c.body.additionalParams, diff --git a/packages/better-auth/src/api/routes/callback.ts b/packages/better-auth/src/api/routes/callback.ts index bbb77d14c4..a042f82756 100644 --- a/packages/better-auth/src/api/routes/callback.ts +++ b/packages/better-auth/src/api/routes/callback.ts @@ -172,7 +172,7 @@ export const callbackOAuth = createAuthEndpoint( code: code, codeVerifier, deviceId: device_id, - redirectURI: `${c.context.baseURL}/callback/${provider.id}`, + redirectURI: `${c.context.baseURL}${provider.callbackPath}`, }); } catch (e) { c.context.logger.error("", e); diff --git a/packages/better-auth/src/api/routes/sign-in.ts b/packages/better-auth/src/api/routes/sign-in.ts index d48174b3f1..57e878236a 100644 --- a/packages/better-auth/src/api/routes/sign-in.ts +++ b/packages/better-auth/src/api/routes/sign-in.ts @@ -349,7 +349,7 @@ export const signInSocial = () => const url = await provider.createAuthorizationURL({ state, codeVerifier, - redirectURI: `${c.context.baseURL}/callback/${provider.id}`, + redirectURI: `${c.context.baseURL}${provider.callbackPath}`, scopes: c.body.scopes, loginHint: c.body.loginHint, additionalParams: c.body.additionalParams, diff --git a/packages/better-auth/src/plugins/generic-oauth/generic-oauth.test.ts b/packages/better-auth/src/plugins/generic-oauth/generic-oauth.test.ts index df7aacdb4c..335f6e1f0a 100644 --- a/packages/better-auth/src/plugins/generic-oauth/generic-oauth.test.ts +++ b/packages/better-auth/src/plugins/generic-oauth/generic-oauth.test.ts @@ -2906,3 +2906,124 @@ describe("oauth2", async () => { }); }); }); + +/** + * @see https://github.com/better-auth/better-auth/issues/4151 + * @see https://github.com/better-auth/better-auth/issues/9593 + */ +describe("redirect_uri composition under dynamic baseURL", async () => { + const dynamicServer = new OAuth2Server(); + await dynamicServer.start(); + const dynamicPort = Number(dynamicServer.issuer.url?.split(":")[2]!); + + afterAll(async () => { + await dynamicServer.stop(); + }); + + beforeAll(async () => { + await dynamicServer.issuer.keys.generate("RS256"); + }); + + async function getAuthorizeRedirectUri( + auth: { handler: (request: Request) => Promise }, + signInPath: string, + host: string, + providerId: string, + ) { + const response = await auth.handler( + new Request(`http://${host}${signInPath}`, { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ + provider: providerId, + callbackURL: "/dashboard", + disableRedirect: true, + }), + }), + ); + const json = (await response.json()) as { url?: string }; + expect(json.url).toBeDefined(); + const authUrl = new URL(json.url!); + return authUrl.searchParams.get("redirect_uri"); + } + + it("composes an absolute redirect_uri for a generic-oauth provider at the default basePath", async () => { + const { auth } = await getTestInstance({ + baseURL: { allowedHosts: ["localhost:3000"] }, + plugins: [ + genericOAuth({ + config: [ + { + providerId: "dynamic-oauth-test", + discoveryUrl: `http://localhost:${dynamicPort}/.well-known/openid-configuration`, + clientId: "test-client-id", + clientSecret: "test-client-secret", + }, + ], + }), + ], + }); + + const redirectUri = await getAuthorizeRedirectUri( + auth, + "/api/auth/sign-in/social", + "localhost:3000", + "dynamic-oauth-test", + ); + + expect(redirectUri).toBe( + "http://localhost:3000/api/auth/oauth2/callback/dynamic-oauth-test", + ); + }); + + it("composes an absolute redirect_uri for a generic-oauth provider at a custom basePath", async () => { + const { auth } = await getTestInstance({ + baseURL: { allowedHosts: ["localhost:3000"] }, + basePath: "/auth", + plugins: [ + genericOAuth({ + config: [ + { + providerId: "dynamic-oauth-test", + discoveryUrl: `http://localhost:${dynamicPort}/.well-known/openid-configuration`, + clientId: "test-client-id", + clientSecret: "test-client-secret", + }, + ], + }), + ], + }); + + const redirectUri = await getAuthorizeRedirectUri( + auth, + "/auth/sign-in/social", + "localhost:3000", + "dynamic-oauth-test", + ); + + expect(redirectUri).toBe( + "http://localhost:3000/auth/oauth2/callback/dynamic-oauth-test", + ); + }); + + it("composes an absolute redirect_uri for a built-in social provider", async () => { + const { auth } = await getTestInstance({ + baseURL: { allowedHosts: ["localhost:3000"] }, + socialProviders: { + google: { + clientId: "google-client-id", + clientSecret: "google-client-secret", + }, + }, + }); + + const redirectUri = await getAuthorizeRedirectUri( + auth, + "/api/auth/sign-in/social", + "localhost:3000", + "google", + ); + + expect(redirectUri).toBe("http://localhost:3000/api/auth/callback/google"); + }); +}); diff --git a/packages/better-auth/src/plugins/generic-oauth/index.ts b/packages/better-auth/src/plugins/generic-oauth/index.ts index ed31ca7ac3..c877cf1603 100644 --- a/packages/better-auth/src/plugins/generic-oauth/index.ts +++ b/packages/better-auth/src/plugins/generic-oauth/index.ts @@ -252,6 +252,7 @@ export const genericOAuth = ( genericProviders.push({ id: c.providerId, name: c.name ?? c.providerId, + callbackPath: `/oauth2/callback/${c.providerId}`, issuer, allowIdpInitiated: c.allowIdpInitiated, createAuthorizationURL(data) { diff --git a/packages/better-auth/src/plugins/oauth-proxy/index.ts b/packages/better-auth/src/plugins/oauth-proxy/index.ts index 2ae5523ea6..964e9a2638 100644 --- a/packages/better-auth/src/plugins/oauth-proxy/index.ts +++ b/packages/better-auth/src/plugins/oauth-proxy/index.ts @@ -436,7 +436,7 @@ export const oAuthProxy = (opts?: O) => { tokens = await provider.validateAuthorizationCode({ code, codeVerifier: stateData.codeVerifier, - redirectURI: `${ctx.context.baseURL}/callback/${provider.id}`, + redirectURI: `${ctx.context.baseURL}${provider.callbackPath}`, }); } catch (e) { ctx.context.logger.error( diff --git a/packages/core/src/oauth2/oauth-provider.ts b/packages/core/src/oauth2/oauth-provider.ts index e11b670d73..4320a7bd58 100644 --- a/packages/core/src/oauth2/oauth-provider.ts +++ b/packages/core/src/oauth2/oauth-provider.ts @@ -28,6 +28,17 @@ export interface OAuthProvider< O extends Record = Partial, > { id: LiteralString; + /** + * Path under the resolved per-request `baseURL` where this provider's + * OAuth callback handler is mounted. Endpoints compose + * `redirectURI = ctx.context.baseURL + callbackPath` per request, so the + * provider must not hardcode an origin or `baseURL` here. + * + * Built-in social providers use `/callback/`. Plugin-provided OAuth + * providers (e.g. generic-oauth) use their plugin's own lane, such as + * `/oauth2/callback/`. + */ + callbackPath: string; createAuthorizationURL: (data: { state: string; codeVerifier: string; diff --git a/packages/core/src/social-providers/apple.ts b/packages/core/src/social-providers/apple.ts index 6051f6753d..14b98fb6d1 100644 --- a/packages/core/src/social-providers/apple.ts +++ b/packages/core/src/social-providers/apple.ts @@ -99,6 +99,7 @@ export const apple = (options: AppleOptions) => { const tokenEndpoint = "https://appleid.apple.com/auth/token"; return { id: "apple", + callbackPath: "/callback/apple", name: "Apple", async createAuthorizationURL({ state, diff --git a/packages/core/src/social-providers/atlassian.ts b/packages/core/src/social-providers/atlassian.ts index 9e3fe924d1..2d917ca39b 100644 --- a/packages/core/src/social-providers/atlassian.ts +++ b/packages/core/src/social-providers/atlassian.ts @@ -33,6 +33,7 @@ export const atlassian = (options: AtlassianOptions) => { const tokenEndpoint = "https://auth.atlassian.com/oauth/token"; return { id: "atlassian", + callbackPath: "/callback/atlassian", name: "Atlassian", async createAuthorizationURL({ diff --git a/packages/core/src/social-providers/cognito.ts b/packages/core/src/social-providers/cognito.ts index 1d9b5202a5..e1a4ca03eb 100644 --- a/packages/core/src/social-providers/cognito.ts +++ b/packages/core/src/social-providers/cognito.ts @@ -72,6 +72,7 @@ export const cognito = (options: CognitoOptions) => { return { id: "cognito", + callbackPath: "/callback/cognito", name: "Cognito", async createAuthorizationURL({ state, diff --git a/packages/core/src/social-providers/discord.ts b/packages/core/src/social-providers/discord.ts index 93616a259b..49e87b68e3 100644 --- a/packages/core/src/social-providers/discord.ts +++ b/packages/core/src/social-providers/discord.ts @@ -87,6 +87,7 @@ export const discord = (options: DiscordOptions) => { const tokenEndpoint = "https://discord.com/api/oauth2/token"; return { id: "discord", + callbackPath: "/callback/discord", name: "Discord", createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) { const _scopes = options.disableDefaultScope ? [] : ["identify", "email"]; diff --git a/packages/core/src/social-providers/dropbox.ts b/packages/core/src/social-providers/dropbox.ts index 81f37976ee..d8ed59bd31 100644 --- a/packages/core/src/social-providers/dropbox.ts +++ b/packages/core/src/social-providers/dropbox.ts @@ -30,6 +30,7 @@ export const dropbox = (options: DropboxOptions) => { return { id: "dropbox", + callbackPath: "/callback/dropbox", name: "Dropbox", createAuthorizationURL: async ({ state, diff --git a/packages/core/src/social-providers/facebook.ts b/packages/core/src/social-providers/facebook.ts index eb92139e28..b4e9d7adec 100644 --- a/packages/core/src/social-providers/facebook.ts +++ b/packages/core/src/social-providers/facebook.ts @@ -42,6 +42,7 @@ export interface FacebookOptions extends ProviderOptions { export const facebook = (options: FacebookOptions) => { return { id: "facebook", + callbackPath: "/callback/facebook", name: "Facebook", async createAuthorizationURL({ state, diff --git a/packages/core/src/social-providers/figma.ts b/packages/core/src/social-providers/figma.ts index a1ab45e4d5..81baee447c 100644 --- a/packages/core/src/social-providers/figma.ts +++ b/packages/core/src/social-providers/figma.ts @@ -23,6 +23,7 @@ export const figma = (options: FigmaOptions) => { const tokenEndpoint = "https://api.figma.com/v1/oauth/token"; return { id: "figma", + callbackPath: "/callback/figma", name: "Figma", async createAuthorizationURL({ state, diff --git a/packages/core/src/social-providers/github.ts b/packages/core/src/social-providers/github.ts index 37ed63cac2..c08f5ec5a3 100644 --- a/packages/core/src/social-providers/github.ts +++ b/packages/core/src/social-providers/github.ts @@ -62,6 +62,7 @@ export const github = (options: GithubOptions) => { const tokenEndpoint = "https://github.com/login/oauth/access_token"; return { id: "github", + callbackPath: "/callback/github", name: "GitHub", createAuthorizationURL({ state, diff --git a/packages/core/src/social-providers/gitlab.ts b/packages/core/src/social-providers/gitlab.ts index 5ae507ce28..e2b01beb6e 100644 --- a/packages/core/src/social-providers/gitlab.ts +++ b/packages/core/src/social-providers/gitlab.ts @@ -80,6 +80,7 @@ export const gitlab = (options: GitlabOptions) => { const issuerName = "Gitlab"; return { id: issuerId, + callbackPath: `/callback/${issuerId}`, name: issuerName, createAuthorizationURL: async ({ state, diff --git a/packages/core/src/social-providers/google.ts b/packages/core/src/social-providers/google.ts index 25707737e9..e582172e06 100644 --- a/packages/core/src/social-providers/google.ts +++ b/packages/core/src/social-providers/google.ts @@ -56,6 +56,7 @@ export interface GoogleOptions extends ProviderOptions { export const google = (options: GoogleOptions) => { return { id: "google", + callbackPath: "/callback/google", name: "Google", async createAuthorizationURL({ state, diff --git a/packages/core/src/social-providers/huggingface.ts b/packages/core/src/social-providers/huggingface.ts index 35be491570..2d47e594a0 100644 --- a/packages/core/src/social-providers/huggingface.ts +++ b/packages/core/src/social-providers/huggingface.ts @@ -46,6 +46,7 @@ export const huggingface = (options: HuggingFaceOptions) => { const tokenEndpoint = "https://huggingface.co/oauth/token"; return { id: "huggingface", + callbackPath: "/callback/huggingface", name: "Hugging Face", createAuthorizationURL({ state, diff --git a/packages/core/src/social-providers/kakao.ts b/packages/core/src/social-providers/kakao.ts index 8c63beeb58..7067923781 100644 --- a/packages/core/src/social-providers/kakao.ts +++ b/packages/core/src/social-providers/kakao.ts @@ -105,6 +105,7 @@ export const kakao = (options: KakaoOptions) => { const tokenEndpoint = "https://kauth.kakao.com/oauth/token"; return { id: "kakao", + callbackPath: "/callback/kakao", name: "Kakao", createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) { const _scopes = options.disableDefaultScope diff --git a/packages/core/src/social-providers/kick.ts b/packages/core/src/social-providers/kick.ts index df486e8a30..20f0c7c76b 100644 --- a/packages/core/src/social-providers/kick.ts +++ b/packages/core/src/social-providers/kick.ts @@ -32,6 +32,7 @@ export interface KickOptions extends ProviderOptions { export const kick = (options: KickOptions) => { return { id: "kick", + callbackPath: "/callback/kick", name: "Kick", createAuthorizationURL({ state, diff --git a/packages/core/src/social-providers/line.ts b/packages/core/src/social-providers/line.ts index 84ad20dc8d..7e8252eb02 100644 --- a/packages/core/src/social-providers/line.ts +++ b/packages/core/src/social-providers/line.ts @@ -49,6 +49,7 @@ export const line = (options: LineOptions) => { return { id: "line", + callbackPath: "/callback/line", name: "LINE", async createAuthorizationURL({ state, diff --git a/packages/core/src/social-providers/linear.ts b/packages/core/src/social-providers/linear.ts index 78892c2f4d..3c11fdc3d4 100644 --- a/packages/core/src/social-providers/linear.ts +++ b/packages/core/src/social-providers/linear.ts @@ -30,6 +30,7 @@ export const linear = (options: LinearOptions) => { const tokenEndpoint = "https://api.linear.app/oauth/token"; return { id: "linear", + callbackPath: "/callback/linear", name: "Linear", createAuthorizationURL({ state, diff --git a/packages/core/src/social-providers/linkedin.ts b/packages/core/src/social-providers/linkedin.ts index cec105ebcb..495e337db7 100644 --- a/packages/core/src/social-providers/linkedin.ts +++ b/packages/core/src/social-providers/linkedin.ts @@ -31,6 +31,7 @@ export const linkedin = (options: LinkedInOptions) => { return { id: "linkedin", + callbackPath: "/callback/linkedin", name: "Linkedin", createAuthorizationURL: async ({ state, diff --git a/packages/core/src/social-providers/microsoft-entra-id.ts b/packages/core/src/social-providers/microsoft-entra-id.ts index 2c5c2668af..2d5525b966 100644 --- a/packages/core/src/social-providers/microsoft-entra-id.ts +++ b/packages/core/src/social-providers/microsoft-entra-id.ts @@ -148,6 +148,7 @@ export const microsoft = (options: MicrosoftOptions) => { const tokenEndpoint = `${authority}/${tenant}/oauth2/v2.0/token`; return { id: "microsoft", + callbackPath: "/callback/microsoft", name: "Microsoft EntraID", createAuthorizationURL(data) { // Microsoft Entra supports public clients (SPA / native apps with diff --git a/packages/core/src/social-providers/naver.ts b/packages/core/src/social-providers/naver.ts index 5a32b01ce7..d0a2aa78f5 100644 --- a/packages/core/src/social-providers/naver.ts +++ b/packages/core/src/social-providers/naver.ts @@ -43,6 +43,7 @@ export const naver = (options: NaverOptions) => { const tokenEndpoint = "https://nid.naver.com/oauth2.0/token"; return { id: "naver", + callbackPath: "/callback/naver", name: "Naver", createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) { const _scopes = options.disableDefaultScope ? [] : ["profile", "email"]; diff --git a/packages/core/src/social-providers/notion.ts b/packages/core/src/social-providers/notion.ts index b16e84781d..5ec5015984 100644 --- a/packages/core/src/social-providers/notion.ts +++ b/packages/core/src/social-providers/notion.ts @@ -27,6 +27,7 @@ export const notion = (options: NotionOptions) => { const tokenEndpoint = "https://api.notion.com/v1/oauth/token"; return { id: "notion", + callbackPath: "/callback/notion", name: "Notion", createAuthorizationURL({ state, diff --git a/packages/core/src/social-providers/paybin.ts b/packages/core/src/social-providers/paybin.ts index e10101ee25..2c9f31641d 100644 --- a/packages/core/src/social-providers/paybin.ts +++ b/packages/core/src/social-providers/paybin.ts @@ -35,6 +35,7 @@ export const paybin = (options: PaybinOptions) => { return { id: "paybin", + callbackPath: "/callback/paybin", name: "Paybin", async createAuthorizationURL({ state, diff --git a/packages/core/src/social-providers/paypal.ts b/packages/core/src/social-providers/paypal.ts index 6d2be733ba..4dcb03370c 100644 --- a/packages/core/src/social-providers/paypal.ts +++ b/packages/core/src/social-providers/paypal.ts @@ -77,6 +77,7 @@ export const paypal = (options: PayPalOptions) => { return { id: "paypal", + callbackPath: "/callback/paypal", name: "PayPal", async createAuthorizationURL({ state, diff --git a/packages/core/src/social-providers/polar.ts b/packages/core/src/social-providers/polar.ts index 9de75c15ab..19681ed99b 100644 --- a/packages/core/src/social-providers/polar.ts +++ b/packages/core/src/social-providers/polar.ts @@ -36,6 +36,7 @@ export const polar = (options: PolarOptions) => { const tokenEndpoint = "https://api.polar.sh/v1/oauth2/token"; return { id: "polar", + callbackPath: "/callback/polar", name: "Polar", createAuthorizationURL({ state, diff --git a/packages/core/src/social-providers/railway.ts b/packages/core/src/social-providers/railway.ts index 0dad19335f..6cb7f11455 100644 --- a/packages/core/src/social-providers/railway.ts +++ b/packages/core/src/social-providers/railway.ts @@ -28,6 +28,7 @@ export interface RailwayOptions extends ProviderOptions { export const railway = (options: RailwayOptions) => { return { id: "railway", + callbackPath: "/callback/railway", name: "Railway", createAuthorizationURL({ state, diff --git a/packages/core/src/social-providers/reddit.ts b/packages/core/src/social-providers/reddit.ts index bc91af66a8..e731efc205 100644 --- a/packages/core/src/social-providers/reddit.ts +++ b/packages/core/src/social-providers/reddit.ts @@ -24,6 +24,7 @@ export interface RedditOptions extends ProviderOptions { export const reddit = (options: RedditOptions) => { return { id: "reddit", + callbackPath: "/callback/reddit", name: "Reddit", createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) { const _scopes = options.disableDefaultScope ? [] : ["identity"]; diff --git a/packages/core/src/social-providers/roblox.ts b/packages/core/src/social-providers/roblox.ts index 8985a9dca2..c847efcae0 100644 --- a/packages/core/src/social-providers/roblox.ts +++ b/packages/core/src/social-providers/roblox.ts @@ -40,6 +40,7 @@ export const roblox = (options: RobloxOptions) => { const tokenEndpoint = "https://apis.roblox.com/oauth/v1/token"; return { id: "roblox", + callbackPath: "/callback/roblox", name: "Roblox", createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) { const _scopes = options.disableDefaultScope ? [] : ["openid", "profile"]; diff --git a/packages/core/src/social-providers/salesforce.ts b/packages/core/src/social-providers/salesforce.ts index 78131b3a50..1ae5e87f79 100644 --- a/packages/core/src/social-providers/salesforce.ts +++ b/packages/core/src/social-providers/salesforce.ts @@ -62,6 +62,7 @@ export const salesforce = (options: SalesforceOptions) => { return { id: "salesforce", + callbackPath: "/callback/salesforce", name: "Salesforce", async createAuthorizationURL({ diff --git a/packages/core/src/social-providers/slack.ts b/packages/core/src/social-providers/slack.ts index e6a15f2c18..60e8086d1b 100644 --- a/packages/core/src/social-providers/slack.ts +++ b/packages/core/src/social-providers/slack.ts @@ -45,6 +45,7 @@ export const slack = (options: SlackOptions) => { const tokenEndpoint = "https://slack.com/api/openid.connect.token"; return { id: "slack", + callbackPath: "/callback/slack", name: "Slack", createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) { const _scopes = options.disableDefaultScope diff --git a/packages/core/src/social-providers/spotify.ts b/packages/core/src/social-providers/spotify.ts index 77ff1395fc..0492efe7f3 100644 --- a/packages/core/src/social-providers/spotify.ts +++ b/packages/core/src/social-providers/spotify.ts @@ -23,6 +23,7 @@ export const spotify = (options: SpotifyOptions) => { const tokenEndpoint = "https://accounts.spotify.com/api/token"; return { id: "spotify", + callbackPath: "/callback/spotify", name: "Spotify", createAuthorizationURL({ state, diff --git a/packages/core/src/social-providers/tiktok.ts b/packages/core/src/social-providers/tiktok.ts index 15dde612d1..abe84d9709 100644 --- a/packages/core/src/social-providers/tiktok.ts +++ b/packages/core/src/social-providers/tiktok.ts @@ -134,6 +134,7 @@ export const tiktok = (options: TiktokOptions) => { const tokenEndpoint = "https://open.tiktokapis.com/v2/oauth/token/"; return { id: "tiktok", + callbackPath: "/callback/tiktok", name: "TikTok", createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) { const _scopes = options.disableDefaultScope ? [] : ["user.info.profile"]; diff --git a/packages/core/src/social-providers/twitch.ts b/packages/core/src/social-providers/twitch.ts index da048c93c4..5b43ec9f16 100644 --- a/packages/core/src/social-providers/twitch.ts +++ b/packages/core/src/social-providers/twitch.ts @@ -41,6 +41,7 @@ export const twitch = (options: TwitchOptions) => { const tokenEndpoint = "https://id.twitch.tv/oauth2/token"; return { id: "twitch", + callbackPath: "/callback/twitch", name: "Twitch", createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) { const _scopes = options.disableDefaultScope diff --git a/packages/core/src/social-providers/twitter.ts b/packages/core/src/social-providers/twitter.ts index c4998a6ebe..f98abc9425 100644 --- a/packages/core/src/social-providers/twitter.ts +++ b/packages/core/src/social-providers/twitter.ts @@ -107,6 +107,7 @@ export const twitter = (options: TwitterOption) => { const tokenEndpoint = "https://api.x.com/2/oauth2/token"; return { id: "twitter", + callbackPath: "/callback/twitter", name: "Twitter", createAuthorizationURL(data) { const _scopes = options.disableDefaultScope diff --git a/packages/core/src/social-providers/vercel.ts b/packages/core/src/social-providers/vercel.ts index 522ebaaa91..f1336d58bf 100644 --- a/packages/core/src/social-providers/vercel.ts +++ b/packages/core/src/social-providers/vercel.ts @@ -19,6 +19,7 @@ export interface VercelOptions extends ProviderOptions { export const vercel = (options: VercelOptions) => { return { id: "vercel", + callbackPath: "/callback/vercel", name: "Vercel", createAuthorizationURL({ state, diff --git a/packages/core/src/social-providers/vk.ts b/packages/core/src/social-providers/vk.ts index 3ad5a5ba03..e4eb54942e 100644 --- a/packages/core/src/social-providers/vk.ts +++ b/packages/core/src/social-providers/vk.ts @@ -29,6 +29,7 @@ export const vk = (options: VkOption) => { const tokenEndpoint = "https://id.vk.com/oauth2/auth"; return { id: "vk", + callbackPath: "/callback/vk", name: "VK", async createAuthorizationURL({ state, diff --git a/packages/core/src/social-providers/wechat.ts b/packages/core/src/social-providers/wechat.ts index c324deda8f..c08265dbee 100644 --- a/packages/core/src/social-providers/wechat.ts +++ b/packages/core/src/social-providers/wechat.ts @@ -58,6 +58,7 @@ export interface WeChatOptions extends ProviderOptions { export const wechat = (options: WeChatOptions) => { return { id: "wechat", + callbackPath: "/callback/wechat", name: "WeChat", createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) { const _scopes = options.disableDefaultScope ? [] : ["snsapi_login"]; diff --git a/packages/core/src/social-providers/zoom.ts b/packages/core/src/social-providers/zoom.ts index 4772b7901d..3629fa18d9 100644 --- a/packages/core/src/social-providers/zoom.ts +++ b/packages/core/src/social-providers/zoom.ts @@ -151,6 +151,7 @@ export const zoom = (userOptions: ZoomOptions) => { return { id: "zoom", + callbackPath: "/callback/zoom", name: "Zoom", createAuthorizationURL: async ({ state,