VibeFix › Guides

Google login redirects to localhost or loops back to login? Fix Lovable and Supabase sign-in after deploy

Sign in with Google worked perfectly in the preview. Now that the app is live, users click the button, pick their Google account and land on localhost:3000, on a Google redirect_uri_mismatch error, or right back on your login page as if nothing happened. The cause is almost always one of a few URL settings that still point at the old address, or a session that gets lost on the way back. Work through these steps in order; most apps are fixed by step 4.

Updated October 20, 2026 · About 8 minutes to read

1. Work out which failure you have

Open your live site in a private window, open DevTools → Network, tick Preserve log, then click Sign in with Google. A healthy flow goes: your app → <project-ref>.supabase.co/auth/v1/authorize → accounts.google.com → <project-ref>.supabase.co/auth/v1/callback → back to your app. Where it breaks tells you which step to read:

2. Lovable Cloud apps: check Auth settings first

If your app uses Lovable's built-in backend (Cloud), open More → Cloud → Users → Auth settings → Advanced. According to Lovable's docs, publishing sets the Site URL to your lovable.app address and connecting a custom domain adds it to Redirect URLs. But a Site URL you (or an earlier prompt) set by hand is left unchanged, so an old preview or localhost value can stick around. Make the Site URL your real live address and confirm every domain you use is in Redirect URLs (up to 50 are allowed).

You can also ask in the project chat: "Update the auth Site URL and Redirect URLs for my published domain https://yourdomain.com."

3. Your own Supabase project: fix Site URL and Redirect URLs

Apps connected to your own Supabase project get no automatic updates. In the Supabase dashboard go to Authentication → URL Configuration:

https://yourdomain.com/**
https://www.yourdomain.com/**
https://yourapp.lovable.app/**
http://localhost:5173/**

Wildcards follow glob rules where . and / are separators: * stops at a slash, ** matches any path. So https://yourdomain.com/* does not match /auth/callback. Supabase recommends exact paths for production; ** is handy for localhost and preview URLs (for Vercel previews, a pattern like https://*-yourteam.vercel.app/**). Click Save.

4. Google Cloud: the redirect URI is Supabase's callback, not your site

Only needed if you use your own Google OAuth client (your own Supabase project, or Lovable with your own credentials). In Google Cloud Console open Google Auth Platform → Clients (formerly APIs & Services → Credentials) and edit the Web application client:

Then make sure the same Client ID and secret are saved under Authentication → Sign In / Providers → Google in Supabase. Google can take a few minutes to apply changes, so wait before retesting.

5. Send redirectTo from the current origin, never a hardcoded URL

AI-generated code often hardcodes the preview URL or localhost. Search the project for localhost, lovableproject and redirectTo. Build the URL from where the user actually is, and make sure that path is in Redirect URLs:

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

// Email sign-up and password reset links have the same problem:
await supabase.auth.signUp({
  email, password,
  options: { emailRedirectTo: `${window.location.origin}/welcome` },
})
await supabase.auth.resetPasswordForEmail(email, {
  redirectTo: `${window.location.origin}/reset-password`,
})

If you pass redirectTo and your email templates link to {{ .SiteURL }}, switch them to {{ .RedirectTo }} (Authentication → Email Templates) so the email link matches. On Lovable Cloud, the generated sign-in code may use Lovable's own auth helper; ask Lovable to fix the redirect rather than swapping in hand-written code.

6. Pick one domain: www and non-www are different sites

Browsers keep localStorage and cookies per origin. If login starts on https://www.yourdomain.com but Supabase sends the user back to https://yourdomain.com, the new origin has no session and no PKCE code verifier, so the user looks logged out or gets a code-exchange error. The same happens between your lovable.app address and your custom domain.

7. Login loop in a React/Vite app: wait for the session before redirecting

If Google and Supabase both succeed but you land back on /login, a route guard is usually checking for a user before supabase-js has finished reading the session from the URL. It sees "no user", redirects to /login, and the cycle repeats. Track a loading state and listen for the INITIAL_SESSION event:

const [session, setSession] = useState(null)
const [loading, setLoading] = useState(true)

useEffect(() => {
  const { data: { subscription } } = supabase.auth.onAuthStateChange((event, session) => {
    setSession(session)
    if (event === 'INITIAL_SESSION') setLoading(false)
  })
  return () => subscription.unsubscribe()
}, [])

if (loading) return <Spinner />          // don't redirect yet
if (!session) return <Navigate to="/login" />

8. Next.js and other SSR apps: exchange the code in a callback route

Server-rendered apps using @supabase/ssr use the PKCE flow: Supabase sends the user to your redirectTo with ?code=..., and your server must exchange it for a session that's saved in cookies. The minimal Next.js App Router version of Supabase's callback route:

// app/auth/callback/route.ts
import { NextResponse } from 'next/server'
import { createClient } from '@/utils/supabase/server'

export async function GET(request: Request) {
  const { searchParams, origin } = new URL(request.url)
  const code = searchParams.get('code')
  let next = searchParams.get('next') ?? '/'
  if (!next.startsWith('/')) next = '/'
  if (code) {
    const supabase = await createClient()
    const { error } = await supabase.auth.exchangeCodeForSession(code)
    if (!error) return NextResponse.redirect(`${origin}${next}`)
  }
  return NextResponse.redirect(`${origin}/auth/auth-code-error`)
}

9. Test the right way: published URL, new private window

Google doesn't let its sign-in page load inside an iframe, and an editor preview often runs in one, so testing Google login inside the editor can fail even when the live app is fine. Always test on the published URL in a fresh private window. Also:

Still looping? Send us your live URL and a screenshot of the Network redirect chain from step 1 through the free check form or by email to fix@getvibefix.com. We'll tell you exactly which setting is wrong for free, before you pay anything.

FAQ

Why does Supabase redirect to localhost:3000 after Google login?
The project's Site URL is still the default http://localhost:3000, or the redirectTo URL your code sends isn't on the Redirect URLs allow list, so Supabase falls back to the Site URL. Set Authentication → URL Configuration → Site URL to your live domain and add your live callback URL to Redirect URLs.

What redirect URI do I add in Google Cloud Console for Supabase?
Your Supabase project's callback URL, https://<project-ref>.supabase.co/auth/v1/callback (shown on the Google provider page in the Supabase dashboard), not your app's own URL. Your app's domain goes under Authorized JavaScript origins. If you use a Supabase custom domain, add its /auth/v1/callback URL as well.

Do I need to set up Google Cloud Console for a Lovable Cloud app?
Not with the default Managed by Lovable Google sign-in: Lovable handles the OAuth client and redirect URLs. Only if you switched to Your own credentials do you need to add each redirect URI Lovable shows (including new custom domains) in Google Cloud and select them in Lovable.

Why does Google login work in preview but not on my custom domain?
The custom domain is missing from the auth Redirect URLs, or, with your own Google credentials, from the Google OAuth client's authorized redirect URIs. Lovable Cloud adds custom domains to Redirect URLs automatically, but a Site URL you set yourself is never changed, and own-credentials setups need the new redirect URI selected and saved.

What does "PKCE code verifier not found in storage" mean?
The callback tried to exchange the ?code= for a session, but the code verifier saved when login started isn't there. Login must start and finish in the same browser on the same domain (www and non-www count as different), and server-rendered apps must use @supabase/ssr on both client and server so the verifier is stored in cookies.

Still stuck? We'll fix it at a flat price.

VibeFix fixes broken Lovable, Bolt, Cursor, Replit and v0 apps. Request a free check first, and we'll tell you what's wrong and which plan fits before you pay. If we can't fix it, you get a full refund.

Get a free check See pricing

Already know you need help? Quick Fix, $49 (one bug, 24h) · Standard Rescue, $129 · Deploy-Ready, from $199

Get 3 fixes for common vibe-coding bugs each week

One short, free email a week with 3 real fixes for Lovable, Bolt, Cursor, Replit and v0 apps.

By signing up, you agree to get one weekly email from VibeFix at this address. Unsubscribe anytime with the link in every email. We never sell or share your email.