[GH-ISSUE #2710] NextJS app configured with a custom basePath is not working with OAUTH providers #17944

Closed
opened 2026-04-15 16:18:28 -05:00 by GiteaMirror · 6 comments
Owner

Originally created by @navahg on GitHub (May 19, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/2710

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

I have the following NextJS Config:

export default const nextConfig: NextConfig = {
  basePath: 'myapp',
}

And I have the better auth configured as:

export const authConfig = {
  database: drizzleAdapter(db, {
    provider: 'pg',
  }),

  // Supported auths
  emailAndPassword: {
    enabled: true,
    autoSignIn: true,
  },
  socialProviders: {
    google: {
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
      enabled: true,
    },
  },

  // Plugins
  plugins: [nextCookies()],
} satisfies BetterAuthOptions

And .env file as

BETTER_AUTH_URL=http://localhost:3000/myapp

Current vs. Expected behavior

With this setup, when initiate a social sign like:

const { url } = await auth.api.signInSocial({
  body: {
    provider: 'google',
  },
  headers: context.headers,
})

I expect to see the google sign in page with the redirect URI as:

Expected - redirect_uri=http://localhost:3000/myapp/api/auth/callback/google

instead I am seeing:

Actual - redirect_uri=http://localhost:3000/myapp/callback/google

I also tried using basePath in combination with BETTER_AUTH_URL=http://localhost:3000

betterAuth({
  basePath: '/myapp/api/auth',
  ...
})

but running into issues there as well.

What version of Better Auth are you using?

1.2.8

Provide environment information

- OS: MacOS 15.4.1
- Browser: Chrome 136.0.7103.114
- NextJS: 15.3.2

Which area(s) are affected? (Select all that apply)

Backend

Auth config (if applicable)

import { betterAuth } from "better-auth"
import { drizzleAdapter } from "better-auth/adapters/drizzle"
import { nextCookies } from "better-auth/next-js"

const config = {
  database: drizzleAdapter(db, {
    provider: 'pg',
  }),

  // Supported auths
  emailAndPassword: {
    enabled: true,
    autoSignIn: true,
  },
  socialProviders: {
    google: {
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
      enabled: true,
    },
  },

  // Plugins
  plugins: [nextCookies()],
} satisfies BetterAuthOptions

export const auth = betterAuth(config);

Additional context

No response

Originally created by @navahg on GitHub (May 19, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/2710 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce I have the following NextJS Config: ```typescript export default const nextConfig: NextConfig = { basePath: 'myapp', } ``` And I have the better auth configured as: ```typescript export const authConfig = { database: drizzleAdapter(db, { provider: 'pg', }), // Supported auths emailAndPassword: { enabled: true, autoSignIn: true, }, socialProviders: { google: { clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, enabled: true, }, }, // Plugins plugins: [nextCookies()], } satisfies BetterAuthOptions ``` And .env file as ```shell BETTER_AUTH_URL=http://localhost:3000/myapp ``` ### Current vs. Expected behavior With this setup, when initiate a social sign like: ```typescript const { url } = await auth.api.signInSocial({ body: { provider: 'google', }, headers: context.headers, }) ``` I expect to see the google sign in page with the redirect URI as: Expected - `redirect_uri=http://localhost:3000/myapp/api/auth/callback/google` instead I am seeing: Actual - `redirect_uri=http://localhost:3000/myapp/callback/google` I also tried using `basePath` in combination with `BETTER_AUTH_URL=http://localhost:3000` ```typescript betterAuth({ basePath: '/myapp/api/auth', ... }) ``` but running into issues there as well. ### What version of Better Auth are you using? 1.2.8 ### Provide environment information ```bash - OS: MacOS 15.4.1 - Browser: Chrome 136.0.7103.114 - NextJS: 15.3.2 ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript import { betterAuth } from "better-auth" import { drizzleAdapter } from "better-auth/adapters/drizzle" import { nextCookies } from "better-auth/next-js" const config = { database: drizzleAdapter(db, { provider: 'pg', }), // Supported auths emailAndPassword: { enabled: true, autoSignIn: true, }, socialProviders: { google: { clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, enabled: true, }, }, // Plugins plugins: [nextCookies()], } satisfies BetterAuthOptions export const auth = betterAuth(config); ``` ### Additional context _No response_
GiteaMirror added the locked label 2026-04-15 16:18:28 -05:00
Author
Owner

@EvaldoSouza commented on GitHub (May 19, 2025):

I'm having the same problem. I tried the solution given in #1806 but to no avail.

<!-- gh-comment-id:2891083156 --> @EvaldoSouza commented on GitHub (May 19, 2025): I'm having the same problem. I tried the solution given in #1806 but to no avail.
Author
Owner

@pauldemarco commented on GitHub (May 21, 2025):

This is also happening to me when using Expo and EAS Hosting (with an alias). Setting basePath seems to have no effect.

<!-- gh-comment-id:2899060238 --> @pauldemarco commented on GitHub (May 21, 2025): This is also happening to me when using Expo and EAS Hosting (with an alias). Setting basePath seems to have no effect.
Author
Owner

@Kinfe123 commented on GitHub (May 28, 2025):

When a URL already has a path, it returns the original URL without modification so can you guys make sure to pass the full url path component with the baseUrl if you have to and make sure you guys mounted on the right path by default the one on the docs is /api/[...auth] here which is based on the default config make sure ot change that up based on your needs.

<!-- gh-comment-id:2915069671 --> @Kinfe123 commented on GitHub (May 28, 2025): When a URL already has a path, it returns the original URL without modification so can you guys make sure to pass the full url path component with the baseUrl if you have to and make sure you guys mounted on the right path by default the one on the docs is /api/[...auth] here which is based on the default config make sure ot change that up based on your needs.
Author
Owner

@nikelborm commented on GitHub (May 29, 2025):

Hit a similar problem. I had my issue because I set basePath and baseUrl only in one place, but actually I had to set it in many places:

in next-js server-side definition:

import { betterAuth } from "better-auth";

export const auth = betterAuth({
  baseURL: globalThis?.location?.origin,
  basePath: "/auth/api/",
  // ...
});

and in next-js client-side definition:

"use client";
import { createAuthClient } from "better-auth/react";

export const {
  signIn: { email: loginWithEmail },
  signUp: { email: registerWithEmail },
  useSession,
} = createAuthClient({
  baseURL: globalThis?.location?.origin,
  basePath: "/auth/api/",
});
<!-- gh-comment-id:2918402542 --> @nikelborm commented on GitHub (May 29, 2025): Hit a similar problem. I had my issue because I set basePath and baseUrl only in one place, but actually I had to set it in many places: in next-js server-side definition: ```ts import { betterAuth } from "better-auth"; export const auth = betterAuth({ baseURL: globalThis?.location?.origin, basePath: "/auth/api/", // ... }); ``` and in next-js client-side definition: ```ts "use client"; import { createAuthClient } from "better-auth/react"; export const { signIn: { email: loginWithEmail }, signUp: { email: registerWithEmail }, useSession, } = createAuthClient({ baseURL: globalThis?.location?.origin, basePath: "/auth/api/", }); ```
Author
Owner

@navahg commented on GitHub (May 30, 2025):

Ok, so if I make the baseURL to include the domain, the base path, and the API mount path, things then seem to work.

export const authConfig = {
  baseURL: 'http://localhost:3000/myapp/api/auth',
  ...
}

It seems like when the baseURL has a path in it, whatever you set for the basePath is ignored. This seems to happen when initializing the auth instance and getBaseURL is called to determine the URL. This ignores the basePath if the baseURL already has a path in it. Not sure if this is by design, but a bit counter intuitive and easy to miss.

If this is in fact by design, can this be doc'ed somewhere?

<!-- gh-comment-id:2923054994 --> @navahg commented on GitHub (May 30, 2025): Ok, so if I make the baseURL to include the domain, the base path, and the API mount path, things then seem to work. ```typescript export const authConfig = { baseURL: 'http://localhost:3000/myapp/api/auth', ... } ``` It seems like when the baseURL has a path in it, whatever you set for the `basePath` is ignored. This seems to happen when initializing the auth instance and `getBaseURL` is called to determine the URL. This ignores the `basePath` if the `baseURL` already has a path in it. Not sure if this is by design, but a bit counter intuitive and easy to miss. If this is in fact by design, can this be doc'ed somewhere?
Author
Owner

@Kinfe123 commented on GitHub (May 30, 2025):

yeah it is infact by design will doc'ed it somewhere!

<!-- gh-comment-id:2923694379 --> @Kinfe123 commented on GitHub (May 30, 2025): yeah it is infact by design will doc'ed it somewhere!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#17944