All guidesMore providers: databases, auth, hosting, email and payments
On this page

Better Auth question

VercelBetter Auth

Why does Better Auth social login fail with redirect_uri_mismatch on Vercel?

By Ohad Krispin, founder of VibeRaven · LinkedIn

Better Auth builds the redirect_uri it sends to Google, GitHub or another provider from its base URL, so the provider answers "Error 400: redirect_uri_mismatch" when that URL is not registered in its console. The usual cause is BETTER_AUTH_URL still being http://localhost:3000 in Vercel, or not being set for the environment that served the request. In a local test, a baseURL of http://localhost:3000 sent redirect_uri=http://localhost:3000/api/auth/callback/google for a request that reached the production domain. Set BETTER_AUTH_URL to your production origin for Production, register https://your-domain/api/auth/callback/google, and redeploy. Reproduced with better-auth 1.7.14 on 2026-10-31.

Which redirect URI do I register for Better Auth?

Better Auth's OAuth docs give the default callback path as /api/auth/callback/ followed by the provider name, and its Google guide says to register the localhost version for local development and your production domain version for production. If you change the base path of the auth routes, the redirect URL changes with it. Google says the value must match an authorized redirect URI exactly, including the http or https scheme, the case and any trailing slash.

Authorized redirect URIs (Google Cloud Console)
http://localhost:3000/api/auth/callback/google
https://my-app.com/api/auth/callback/google

How does Better Auth choose its base URL?

The options reference says it uses the baseURL option, then the BETTER_AUTH_URL variable, then the incoming request. In the source (utils/url.ts) the variables are tried in this order and the first one with a value wins: BETTER_AUTH_URL, NEXT_PUBLIC_BETTER_AUTH_URL, PUBLIC_BETTER_AUTH_URL, NUXT_PUBLIC_BETTER_AUTH_URL, NUXT_PUBLIC_AUTH_URL, then BASE_URL unless it is "/". A string baseURL in the config beats all of them. With none set, Better Auth logs "[better-auth] Base URL is not set" and takes the origin from the request, so a preview or a new custom domain sends a redirect_uri that nobody registered. The Google guide says without a configured baseURL the callback URL may default to localhost, which fails in production.

baseURL not set, POST /api/auth/sign-in/social sent to https://my-app.example.com
  redirect_uri=https://my-app.example.com/api/auth/callback/google
baseURL set to http://localhost:3000, same request
  redirect_uri=http://localhost:3000/api/auth/callback/google

Why does it fail only on previews or only on my custom domain?

Vercel applies a variable to the environments you select, so a BETTER_AUTH_URL added for Production only is missing on Preview deployments, and a change reaches only new deployments. VERCEL_PROJECT_PRODUCTION_URL holds a production domain without the https:// scheme, so a value built from it needs the scheme added. A preview URL changes with every deployment, which a provider console cannot list one by one: for Better Auth's own origin check on previews, see the allowedHosts setup, and for the provider side, the three URLs that change with a domain.

Checklist

How to fix it, then check the fix

  1. 01Start sign-in on the deployment and read the redirect_uri parameter in the address bar of the provider's page. That is the URL Better Auth sent.
  2. 02
    Find every place the app sets the base URL, including committed .env files:
    grep -rnE "BETTER_AUTH_URL|NEXT_PUBLIC_BETTER_AUTH_URL|baseURL" --exclude-dir=node_modules --exclude-dir=.next .
  3. 03
    Set BETTER_AUTH_URL to your production origin, with https://, for Production, and check which value Preview gets:
    vercel env add BETTER_AUTH_URL production
  4. 04In the provider console, add the exact callback URL: your production origin plus /api/auth/callback/ and the provider name.
  5. 05If NEXT_PUBLIC_BETTER_AUTH_URL holds a localhost value, change it and rebuild: Next.js copies NEXT_PUBLIC_ values into the bundle at build time.
  6. 06Redeploy, start sign-in again, and check the redirect_uri parameter shows your production origin and the provider page opens without an error.

Related

Sources

Official docs behind this checklist

FAQ

FAQ for builders before launch

Does it matter that the error comes from Google and not from Better Auth?

Yes. Google compares the redirect_uri in the request with the URIs registered for the client ID and answers redirect_uri_mismatch when none matches. Better Auth is not involved in that step, because the browser is already on the provider's page. Change the URL Better Auth sends, or the list in the console.

Does this apply to GitHub or other providers?

The OAuth docs give the default callback path as /api/auth/callback/ plus the provider name, built from the same base URL, so for GitHub you register the production origin with /api/auth/callback/github.