Supabase Google OAuth redirects to localhost after login: how to fix it

Updated 27 Oct 2026 · Pewterkit Guides

If Google sign-in succeeds but your live site sends users to http://localhost:3000, the usual cause is that Supabase's Site URL is still the default http://localhost:3000 and your redirectTo is missing, not on the Redirect URLs list, or itself set to localhost. Set the Site URL to your production domain, pass redirectTo in signInWithOAuth, and add that exact URL to Supabase's Redirect URLs list.

Why production logins land on localhost

After Google hands the user back to Supabase Auth, Supabase decides where to send them next. Three things feed that decision:

  1. Site URL. Supabase's docs describe it as the default redirect when your code passes no redirectTo. On new projects (and in the CLI's config.toml) it starts as http://localhost:3000. If you never changed it, every login without redirectTo ends on localhost.
  2. redirectTo that isn't on the allow list. Supabase's own troubleshooting note on "redirects going to localhost instead of the production site URL" says redirectTo only works if the exact URL is in the Redirect URLs setting. Supabase's docs don't spell out what happens to an unlisted URL, but the note ties this mistake to the localhost symptom: if the URL isn't listed, users may end up on the Site URL instead.
  3. redirectTo that is itself localhost. A hardcoded http://localhost:3000/..., or an environment variable such as NEXT_PUBLIC_SITE_URL that was set to localhost when the production bundle was built, sends users there even when everything in Supabase is right.

Google Cloud is not involved in this hop. Google's authorized redirect URI is the Supabase callback (https://<project-ref>.supabase.co/auth/v1/callback), so adding your production domain to Google's redirect URIs won't change where Supabase sends the user.

Step-by-step fix

1. Change the Site URL

In the Supabase dashboard, open Authentication → URL Configuration (as of Oct 2026) and replace http://localhost:3000 with your production origin:

https://example.com

Supabase notes this setting also drives email confirmations and password resets, so it should always point at production.

2. Allow-list the exact production URL

On the same page, under Redirect URLs, add the URL your app will pass as redirectTo, exactly as the browser will request it (same scheme, www or not, path):

https://example.com/auth/callback

Keep a separate entry for local development so localhost keeps working:

http://localhost:3000/**

3. Always pass redirectTo, built from the current origin

Don't rely on the Site URL fallback. Build redirectTo from where the user actually is:

const { error } = await supabase.auth.signInWithOAuth({
  provider: 'google',
  options: {
    redirectTo: `${window.location.origin}/auth/callback`,
  },
})

If you compute the URL from environment variables instead (common with Next.js on Vercel), use a helper that prefers your production URL and normalizes the format. This is the pattern from Supabase's redirect URL guide:

const getURL = () => {
  let url =
    process?.env?.NEXT_PUBLIC_SITE_URL ?? // set to your production URL in the production env
    process?.env?.NEXT_PUBLIC_VERCEL_URL ?? // Vercel system environment variable
    'http://localhost:3000/'
  url = url.startsWith('http') ? url : `https://${url}`
  url = url.endsWith('/') ? url : `${url}/`
  return url
}

await supabase.auth.signInWithOAuth({
  provider: 'google',
  options: { redirectTo: `${getURL()}auth/callback` },
})

NEXT_PUBLIC_* values are inlined at build time in Next.js, so after changing one in your host's settings, redeploy so the new value is in the bundle.

Test this on a preview deployment before relying on it.

4. Check the callback route's final redirect (SSR / PKCE)

If you use a server callback such as app/auth/callback/route.ts, its last redirect decides the final page. Behind a proxy or load balancer, request.url can carry an internal origin. Supabase's example reads x-forwarded-host for this reason:

const forwardedHost = request.headers.get('x-forwarded-host')
const isLocal = process.env.NODE_ENV === 'development'
if (isLocal) return NextResponse.redirect(`${origin}${next}`)
if (forwardedHost) return NextResponse.redirect(`https://${forwardedHost}${next}`)
return NextResponse.redirect(`${origin}${next}`)

Whether your host sets x-forwarded-host depends on its proxy. Test this on a preview deployment before relying on it.

How to confirm it worked

  1. Open your production site in a private window and click "Sign in with Google".
  2. Before choosing an account, read the Google URL: its redirect_uri should be your Supabase callback, not your app.
  3. After choosing an account you should land on https://example.com/auth/callback (then your app), not localhost.
  4. Repeat on http://localhost:3000 to make sure local development still lands locally.

FAQ

Why does Supabase redirect to localhost:3000 after Google login?

Usually because the Site URL is still http://localhost:3000 and your request either had no redirectTo or used a redirectTo that isn't in the Redirect URLs list. Change the Site URL to production and allow-list the exact redirectTo.

Do I need to add my production domain to Google Cloud's redirect URIs?

No. With Supabase, Google redirects to the Supabase callback (https://<project-ref>.supabase.co/auth/v1/callback), and that is the only redirect URI Google needs. Your production URL goes into Supabase's Site URL and Redirect URLs.

I changed the Site URL but users still land on localhost. What now?

Check what your code sends as redirectTo. A hardcoded localhost URL, or a localhost value baked into a production build through an environment variable, overrides the Site URL. Rebuild after fixing the variable.

Can I keep localhost working while production is fixed?

Yes. Keep the Site URL on production and add http://localhost:3000/** to Redirect URLs, then pass redirectTo built from window.location.origin so each environment returns to itself.

Sources

  1. Redirect URLs | Supabase Docs
  2. Why am I being redirected to the wrong url when using auth redirectTo option? | Supabase Docs
  3. Login with Google | Supabase Docs
  4. CLI configuration reference | Supabase Docs
  5. Environment variables | Next.js Docs

How this page was made: drafted with AI from the sources listed, reviewed by Pewterkit. Docs checked 27 Oct 2026. Spotted something out of date? Tell us.

Related guides