FixedLaunchBack

fix guide

Supabase login works locally but fails in production

· · updated

All fix guides

Sign-in works on your machine or in the builder's preview. On the live domain it sends people back to the sign-in page, the email link opens localhost, or Google sign-in shows an error.

The code is usually fine. Supabase and Google tie a few settings to one web address, and those settings still point at the old one. Check these five in order. Each takes a few minutes in a dashboard, no code.

1. Site URL and redirect URLs in Supabase

Open Supabase, then Authentication, then URL Configuration. The Site URL is where confirmation and magic-link emails send people by default. If it still says http://localhost:3000 or the preview address, every email link goes there.

Set the Site URL to your live domain, for example https://yourapp.com. Under Redirect URLs, add every address people sign in from: the live domain, the www version and the preview address. A wildcard like https://yourapp.com/** covers the inner pages.

On Lovable, the preview runs on a lovable.app address. Once you connect your own domain, add it here too.

signs The link in the email opens localhost or the preview. After sign-in you land on the home page instead of where you started.

2. Environment variables on the live host

The live site needs the same Supabase URL and anon (public) key as the preview. The builder keeps them for its own preview, but Vercel or Netlify only have what you added there.

The names depend on the app. Vite apps (Lovable, Bolt) use VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY. Next.js apps use NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY. These values are baked in when the site builds, so redeploy after you add or change them.

Check that both point at the project you test against. A live site wired to a second, empty Supabase project looks like a login bug: the users you created don't exist there.

signs The browser console shows "supabaseUrl is required" or "Invalid API key", or requests go to an address with "undefined" in it.

3. Google or GitHub sign-in settings

In Google Cloud, open your OAuth client. The authorized redirect URI must be the Supabase callback, https://<project-ref>.supabase.co/auth/v1/callback, and your live domain belongs under authorized JavaScript origins.

In Supabase, open Authentication, then Sign In / Providers, and check Google is switched on with the client ID and secret from that same OAuth client. A provider that is off, or holds keys from a different client, fails only for that sign-in button.

Then open the OAuth consent screen. While its publishing status is Testing, only the test users you listed can sign in, so it works for you and fails for everyone else. Publish the app to move it to production.

GitHub sign-in works the same way: the callback URL in the GitHub OAuth app must be the Supabase callback.

signs Google shows redirect_uri_mismatch or "Access blocked". Sign-in works for you and nobody else.

4. Email delivery

Supabase's built-in email sender is meant for trying things out. It only sends to the email addresses of your Supabase team members and allows very few emails an hour. Real users never get the confirmation or password reset email.

Set up your own SMTP sender (Resend, Postmark, Amazon SES or similar) under Authentication, then Emails, then SMTP settings. Then send yourself a reset email from a new address to check it arrives.

signs You get the emails and your users don't, or sign-up fails with "email rate limit exceeded".

5. Sessions that drop on refresh

In a Next.js app on @supabase/ssr, the session lives in cookies and the middleware has to refresh it on each request. If the middleware file is missing, or its matcher skips the pages people use, users look logged out after a refresh or on server-rendered pages.

In a Vite app, a refresh on an inner page like /dashboard that shows a 404 is a hosting problem, not a login one: the host needs a rewrite that sends every path to index.html.

signs Logged in, then logged out after a refresh. Server pages treat a signed-in user as a guest.

Test it like a new user

  1. Open the live site in a private window.
  2. Sign up with an email address you have never used on the app.
  3. Confirm from the email and check the link opens the live domain.
  4. Refresh a logged-in page, then sign out and sign back in.
  5. If you have Google sign-in, try it from a Google account that isn't yours.

Common questions

Why does my Supabase magic link open localhost instead of my live site?

Supabase sends confirmation and magic-link emails to the Site URL, and that setting still points at localhost or the preview address. Open Authentication, then URL Configuration, and set the Site URL to your live domain. Add every address you sign in from under Redirect URLs, including the www version.

Why does Google sign-in fail on my live site but work for me?

The OAuth consent screen is probably still in Testing. In that mode only the test users you listed can sign in, so it works for you and fails for everyone else. Publish the app to move it to production. Also check the redirect URI is the Supabase callback.

Why don't my users get the confirmation or password reset email?

Supabase's built-in email sender is meant for testing. It only sends to your Supabase team members and allows very few emails an hour, so real users never get them. Set up your own SMTP sender under Authentication, then Emails, then SMTP settings.

Still stuck?

Not sure this is the cause? Paste your app's link into the free scan. It lists what a visitor's browser can see, like leaked keys and exposed files, worst first. The score is free; every fix as a prompt for your builder is $9, one-time.

Want a person to look inside? See the diagnosis

More fix guides

See all fix guides