# Login that works after you publish: the live-site checklist for a vibe-coded app

> Sign-in works in the preview and loops, lands on localhost or hangs on the live site. Six checks, in the order a stranger hits them, with the exact error strings and the setting behind each one.

- Source: https://www.buildbase.app/guides/login-that-works-after-you-publish
- Section: Guides
- Author: Dharmendra Jagodana
- Published: 2026-10-27

## In short

Login that works in the preview and fails on the published site comes down to an address: the sign-in provider only returns to URLs it was told about, and the live one was never added. Six checks in order: the redirect address, the Google client, the confirmation email, the session, sign-out, a second browser.

A Replit review from 17 October 2026 reads, in full: "Users can't log in."
A paid-fix vendor advertises on Mastodon with the exact symptom: "lovable
login works in preview, then loops or dumps you on localhost after
publish?" And on dev.to, the largest troubleshooting cluster we found for
any builder, ten posts in thirty days, is Lovable sign-in that works for
the builder and fails for everyone else.

It is nearly always the same thing. Sign-in happens on a page somebody else
hosts (Supabase, Lovable Cloud, Bolt Cloud, Google, BuildBase's hosted
page), and that page only sends people back to addresses it has been told
about. The preview address was told about. The published one, and the
custom domain you added on Friday, were not. Nothing in the app is broken,
which is why no amount of prompting fixes it, and why a loop of fixes is
how the credits go.

This is a checklist, not a tutorial: six checks in the order a stranger
hits them, each with the symptom, the error string if there is one, the
setting behind it, and how to prove it is fixed. Run every one on the
**published** site, in a private window, as a second person, never as
yourself in the editor's preview. The settings and limits quoted were read
from each vendor's own docs on 27 October 2026.

> **Before you start:** A published app with a sign-in of any kind (the builder's built-in, your own
> Supabase project, or BuildBase), a second email address you control, and a
> second browser or a private window. For the Google check, access to the Google
> Cloud Console project that holds the OAuth client.

## First, find out who does your sign-in

Before any check, name the thing that signs people in, because every
setting below lives in a different place depending on the answer. Most
builders have given you one of four:

| Who signs people in                                                     | How to tell                                                                                              | Where the allow list lives                                                           |
| ----------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| The builder's built-in backend (Lovable Cloud, Bolt Cloud, Replit Auth) | The Users list is inside the builder, and you never created a Supabase or BuildBase account for this app | The builder's own auth settings; Lovable and Bolt manage most of it when you publish |
| Your own Supabase project                                               | There is a Supabase dashboard for this app and the code calls `supabase.auth`                            | Supabase, Authentication, URL Configuration: the Site URL and the Redirect URLs      |
| BuildBase's hosted page                                                 | The code has a `SaaSOSProvider`, three `/api/auth/*` routes and a `bb-session` cookie                    | The auth client in the BuildBase console, under User Management, Authentication      |
| Something the agent wrote itself                                        | A `users` table, a password hash, a `jsonwebtoken` or `iron-session` dependency                          | Nowhere; the redirect is whatever the code does, and the code is the setting         |

The fourth row is the one to worry about. There is no allow list because
the agent wrote its own sign-in, and the checks below still apply, but the
"setting" is a line of code the agent chose. [What a coding agent builds
when nobody tells it
otherwise](/blog/what-a-coding-agent-builds-when-nobody-tells-it-otherwise)
is what that line usually looks like.

## 1. The redirect address: where sign-in sends people back

Symptom: sign-in works in the preview; on the live site it loops back to
the sign-in page, lands on `localhost:3000`, or shows "redirect URL not
allowed". Cause: the live address is not on the provider's allow list, so
the provider falls back to its default, which is the preview or localhost.

A published app has more addresses than it looks. Lovable gives you a
preview address, a published `something.lovable.app` address, and your
custom domain if you added one; v0 and Vercel give you a preview address
per deployment and a production domain; Bolt gives you a Netlify address
and your domain. Each is a different string to the provider, and an allow
list that holds one of them holds one of them. Register the published
address and the custom domain as a matter of course, and the preview only
if you test sign-in there.

The settings, by provider:

**Supabase (your own project, or the one a builder created for you).** The
Site URL is the default redirect when no `redirectTo` is given, and the
docs tell you to change it "from `http://localhost:3000` to your production
URL". Redirect URLs live on the URL Configuration page; the `redirectTo`
your code passes must match that list. Wildcards exist (`*` matches within
one path segment, `**` across them), and the docs keep them for local and
preview work: "we recommend setting the exact redirect URL path for your
site URL in production".

**Lovable Cloud.** The built-in sign-in allows up to 50 redirect addresses
per app. If the app uses your own Supabase project instead, Lovable's
sign-in docs say it does not update that project's Site URL or redirect
URLs for you; you add the published address and the custom domain in the
Supabase dashboard yourself.

**Bolt Cloud.** Bolt's auth settings carry a Site URL ("the primary live
URL of your app") and a URI allow list; new projects default to
`localhost:3000`, which the docs say "does not work for live applications".
Bolt usually updates these when you publish, and the docs add that you may
need to edit them by hand, "especially with multiple domains".

**BuildBase.** Each auth client has a list of redirect URLs, and the hosted
sign-in page returns only to one of them, path included. A wildcard can
stand in for one leftmost subdomain on a domain you own
(`https://*.app.example.com/sign-in`), and never on a public suffix, so
`*.lovable.app` and `*.vercel.app` are refused. Register the published
address, the custom domain, and `localhost` for local work, each once.
[Auth clients, redirect URLs and environments](/guides/auth-clients-redirect-urls-and-environments)
is the pattern for keeping preview, staging and production apart without
sharing a client.

How to prove it: open the published site in a private window, start
sign-in, and read the address bar when it fails. If it says `localhost`,
the Site URL is the default. If it says "not allowed" or "mismatch", the
address differs from the registered one by a trailing slash, `www`, `http`
versus `https`, or the path. Fix the one character, and try again from a
fresh private window, because the old one may have cached the failure.

The four ways an address differs, because every one of them has cost
someone an afternoon: `https://app.example.com/sign-in` is not
`https://app.example.com/sign-in/` (the slash), not
`https://www.app.example.com/sign-in` (the `www`), not
`http://app.example.com/sign-in` (the scheme), and not
`https://app.example.com/` (the path). Allow lists compare strings, not
intentions.

If you want the agent to do the registering, give it the strings rather
than the job, because an agent asked to "fix login on the live site" will
change code, and the code was never wrong:

```text
Do not change any sign-in code. In the sign-in provider's settings, set the Site URL to https://<published address> and add these redirect URLs exactly, with no wildcard: https://<published address>/sign-in, https://<custom domain>/sign-in, http://localhost:3000/sign-in. Then tell me which settings page you changed and what it now contains.
```

**Correcting potential issues.** If the agent answers by editing the
sign-in code anyway, paste: "Revert that change. The problem is the
provider's allow list, not the code; show me the current Site URL and
redirect list before changing anything else." On a builder that manages
the list for you (Lovable Cloud, Bolt Cloud), publishing again after adding
a custom domain is often the whole fix, because the builder updates the
list on publish; Bolt's docs say exactly that, with the caveat about
multiple domains.

## 2. The Google client: `redirect_uri_mismatch`

Symptom: the Google button opens Google's page, which shows "Error 400:
redirect_uri_mismatch", or returns to the app with nothing signed in.
Cause: the address Google was asked to return to is not one of the
authorized redirect URIs on your OAuth client, exactly.

This one has a second allow list, and it is Google's, not your provider's.
Whoever handles the sign-in (Supabase, Bolt Cloud, BuildBase) has one
callback address that Google must know; Bolt's docs, for example, show the
origin and redirect URIs to paste into Google Cloud Console when you turn
Google on. That address does not change when you publish, which is why
this check passes for most people. It fails when the client was created
for a different provider, when a second provider was added later, or when
someone pasted the app's address instead of the provider's callback.

The Figma Make community thread that opened on 22 July 2025, "Google
signup works but no access to app", stayed open into September with no
root cause given; the symptom in it is this check and the one before it
together: Google succeeded, then the provider returned to an address the
app did not expect.

How to prove it: read the `redirect_uri` in Google's error page, copy it
character for character into the OAuth client's authorized redirect URIs,
save, wait a few minutes, retry from a private window. If your sign-in is
BuildBase, [social login in Next.js](/guides/social-login-nextjs) shows the
one callback address to register and the two values to paste back.

## 3. The confirmation email that only you receive

Symptom: you signed up fine; a stranger signs up and the confirmation
email never arrives, or arrives an hour later, or lands in spam. Cause: the
sender is a development sender with limits you never hit, because you were
inside them.

Supabase's docs on custom SMTP say it plainly about the built-in sender:
"Supabase Auth will refuse to deliver messages to addresses that are not
part of the project's team", the limit is "2 messages per hour", and the
server "is not meant for production use". You are on the team. Your
customers are not. The dev.to writer who put it best: "Then a real person
signs up, never gets the confirmation email, and you never hear from them
again."

The fix on Supabase is a custom SMTP sender (Resend, SES, Postmark,
SendGrid and others are named in the docs) set in the project's auth
settings, after which mail goes to everyone, with a limit of 30 an hour
until you raise it on the rate-limits page. On BuildBase, sign-in emails go
out through your organization's sending domain (Google, Mailgun, Amazon
SES or your own SMTP), which you set once for every email the platform
sends, and the [guide on email landing in
spam](/guides/transactional-email-landing-in-spam) covers the domain
records that keep it out of the junk folder.

How to prove it: sign up with an address at a provider you do not use for
work (a Gmail account if you build on Outlook, or the reverse), and time
the email. Then open it on a phone and look at the sender name and
address. "noreply@mail.app.supabase.io" is the development sender; your own
domain is the fix.

## 4. The session after a reload, and after a week

Symptom: sign-in works; reloading the page signs you out, or everything is
fine until a week later when every user is signed out at once. Cause: the
session is held in the wrong place, or on the wrong host.

The right place is a cookie the browser cannot read, set by your server
after the sign-in code is exchanged, with a lifetime you chose. On
BuildBase that cookie is 30 days by default, which is the
[default session length](/guides/token-expired-mid-request), and the Vite,
Next.js and Lovable guides all set it the same way. A session kept in
`localStorage` by the browser survives reloads but can be read by any
script on the page, which is the thing the 2025 Lovable exposure and the
2026 Moltbook leak had in common: a key the browser held.

The wrong host is subtler. A cookie set on `app.example.com` is not sent
to `example.com`, and a cookie set on the published `*.lovable.app`
address does not follow you to the custom domain. If sign-in works on one
address and not the other, that is the cookie, and [a session cookie not
shared across subdomains](/guides/session-cookie-not-shared-across-subdomains)
is the two-line fix.

How to prove it: sign in, close the browser entirely, open the published
site again. Still signed in. Then open the same site on the custom domain
in the same browser. Still signed in, or you have the subdomain problem.
And if your app uses Next.js middleware to guard pages, the symptom "the
page reloads forever after sign-in" has its own guide:
[middleware redirect loop after login](/guides/nextjs-middleware-redirect-loop-after-login).

## 5. Sign-out that actually signs out

Symptom: a user signs out, presses back, and is still inside. Or signs out
on a laptop and stays signed in on a phone. Cause: sign-out cleared a value
in the browser and told the server nothing.

A sign-out has to end the session where it lives, on the server, so that
the cookie, the phone and the tab that was left open all stop working at
once. On BuildBase, `onSignOut` calls your sign-out route, which clears the
cookie, and the SDK revokes the session on the platform, so a device list
shows it gone and the other devices lose it too. A generated sign-out
usually does only the first half.

How to prove it: sign in on two browsers as the same person. Sign out on
one. Reload the other. If it is still signed in, the server was never
told. The device list on the account screen is the honest check: a
session that is signed out should not be listed.

The same list is the answer to the first support email every app gets,
"I think someone else is logged into my account". Every BuildBase user has
a list of their devices and can sign out one or all of them, and so can
you, as the owner, from the console; a generated app has neither, because
nobody asked, and the only way to end a stolen session is to change the
password and hope. If your sign-in is the builder's built-in, check
whether the Users view offers the same; as of 27 October 2026, Lovable's
shows sign-up and last sign-in times and the methods used, and Replit's
Users tab lists people and last sign-in, and neither documents a way to
end a session from there.

## 6. The second person, and the second browser

Symptom: none yet, because nobody has tried. This is the check that finds
the five above before a customer does.

Every check on this list fails for a stranger first and for you last,
because your browser carries the preview's cookies, your email is on the
project's team, and your Google account already consented. So the last
check is the first one to run: a private window, a second email address,
a phone on mobile data rather than your Wi-Fi, and the published address
typed by hand rather than clicked from the editor.

Walk the whole path: sign up, confirm, sign out, sign in, close the
browser, reopen, forgot password. Then do it once more on the custom
domain. Ten minutes, and it is the same ten minutes a stranger will spend
before deciding whether your app is real.

## What prompting it instead costs

The reason this is a checklist and not a prompt: the fix is a setting, and
an agent asked to fix it will change code. Lovable's own pricing page gives
1.20 credits as the example cost of adding authentication in build mode
(read 27 October 2026), and the complaint that dominates every builder's
reviews is the loop: "repeated 'fixes' that did not fix the problem", as
one 1-star Lovable review from 12 October 2026 puts it, and "You will then
spend DAYS and credits telling it to do the same thing 15 times", from
another in September. Fifteen attempts at 1.20 credits is a fifth of a Pro
plan's monthly 100, spent on code that was never wrong. The six checks
above cost nothing but ten minutes, and the one prompt worth sending is
the one in check 1 that names the addresses and forbids code changes.

> **Key takeaway:** Sign-in that works in preview and fails live is an address problem, not a code
> problem. Find the allow list, add the exact live address, test as a stranger
> from a private window. Prompting the agent to "fix login" will spend credits
> on code that was never wrong.

## Where the built-in sign-in is the better pick

If your app has one user per account and the built-in sign-in works for
strangers after the six checks above, keep it. Lovable Cloud, Bolt Cloud
and Replit Auth manage their own redirect addresses when you publish, and
Lovable's built-in sign-in adds SAML SSO and OIDC of its own, where
BuildBase's [enterprise SSO](/enterprise) runs through your own WorkOS
account on the Enterprise plan. An external sign-in adds a client to
register and an address to keep in step, and for a single-user app that is
work for nothing.

Choose a hosted sign-in on your own domain when you want one address to
register per environment instead of one per builder preview, methods that
are switches rather than code (passkeys, magic links, Google, GitHub,
Microsoft, Apple and the rest), a device list and a sign-out that ends the
session everywhere, and the teams and plans layer on top. [Should you run
auth on your own domain](/guides/should-you-run-auth-on-your-own-domain)
is the decision in full, and [the launch
checklist](/guides/vibe-coded-app-launch-checklist) is the other nineteen
things to check before strangers arrive.

## What breaks, and how you can tell

**Loops to the sign-in page on the live site.** Check 1. The live address
is not on the allow list, or differs by one character.

**Lands on `localhost:3000` after sign-in.** Check 1. The Site URL is still
the default. Supabase's and Bolt's docs both name that default.

**Error 400: redirect_uri_mismatch.** Check 2. Google's authorized redirect
URIs do not include the provider's callback address exactly.

**Confirmation email arrives for you and nobody else.** Check 3. The
development sender delivers only to the project's team, at two an hour.

**Signed out on every reload.** Check 4. The session route is not deployed,
or the cookie is set on another host.

**Signed out, pressed back, still inside.** Check 5. Sign-out never reached
the server.

**"Users can't log in", and you cannot reproduce it.** Check 6. You are
testing as yourself. Private window, second email, phone on mobile data.

## Install

If the fix for your app is a hosted sign-in page with one address to
register, the SDK and the CLI write the sign-in routes for you:

```bash
npm i @buildbase/sdk
npx buildbase init --org-id <your 24-character org id>
```
