Sign-in worked perfectly in preview. Then you deployed, and now one of these happens:
- confirmation emails link to
localhost:3000 - Google sign-in bounces somewhere strange
- users land back on the login page
This is one of the most common issues with apps built in Lovable, Bolt, Replit, v0 and Cursor. The cause is nearly always configuration, not code.
1. Site URL still points at localhost
In Supabase Dashboard → Authentication → URL Configuration, the Site URL is the default redirect for:
- email confirmations
- password resets
- any sign-in that doesn't pass a valid
redirectTo
Supabase's docs specifically tell you to change it from http://localhost:3000 to your production URL. Wildcards aren't allowed here.
2. Your redirect URL isn't on the allow list
If your code passes redirectTo or emailRedirectTo and that exact URL isn't on the Redirect URLs list, Supabase silently falls back to the Site URL. That's why users "randomly" end up on localhost.
The match is strict:
httpvshttpscounts as different- a trailing slash counts
- a double slash counts, e.g. from
${window.location.href}/callbackwhen the href already ends in/
Add these entries:
https://yourdomain.com/**(or the exact callback path)http://localhost:3000/**for local development- preview patterns if you use them. Supabase's docs suggest
https://*-<team>.vercel.app/**for Vercel andhttps://**--<site>.netlify.app/**for Netlify.
In code, build the redirect from the current origin: redirectTo: \${window.location.origin}/auth/callback``.
3. OAuth provider callback mismatch
For Google, GitHub and other providers, the provider's console must list Supabase's callback URL (https://<project-ref>.supabase.co/auth/v1/callback). Your own domain also has to be in Supabase's Redirect URLs. If you moved to a custom domain or custom auth domain, update both sides.
4. Missing environment variables in production
A blank page or an error like supabaseUrl is required means the production build didn't get your Supabase URL and anon key. On Netlify and Vercel, VITE_ variables are baked in at build time, so add them in the host's settings and redeploy. Editing them afterwards doesn't change a site that's already built.
5. The dashboard shows the new Site URL but emails still say localhost
Check your email templates. A hard-coded URL there overrides everything else. Also capture one real bad link and compare it piece by piece with your settings. Some users on Supabase's GitHub reported that restarting the project from the dashboard fixed stale behaviour. Treat that as a last resort, not a first step.
6. Login loop after a successful sign-in
- Make sure your callback route actually exchanges the code for a session (PKCE flow) before redirecting.
- Check that route guards wait for the session to load, rather than redirecting to
/loginwhile it's stillnull. - On SPA hosts, refreshing
/auth/callbackmust serveindex.html. Add an SPA rewrite, or the callback 404s.
Quick test script
- Sign up with a fresh email on production.
- Open the confirmation link on a different device.
- Log out, log in, then refresh a protected page.
- Request a password reset.
If all four work, your auth is healthy.
How FlowCanary's free check detects this
FlowCanary's free scan loads your /signup and /login pages in a real browser. It reports:
- pages that return errors or render blank
- console errors such as
supabaseUrl is required - failed requests to your auth backend
- broken links
Each finding comes with a paste-ready fix prompt for your AI builder. Daily monitoring of the full signup/login flow, with alerts, is coming next.