afterbuild/ops
Solution

Fix broken AI app auth — before users get locked out.

Auth is the most brittle part of every AI-built app. It works in the builder's preview, then breaks the moment you deploy. Here's the pattern we see and how we fix it.

Quick verdict

What a fixed auth flow looks like: OAuth redirects to your production domain. Sessions refresh automatically. Password reset works. Supabase RLS is tied to auth.uid(). onAuthStateChange handles every state transition. Under 48 hours to diagnose and scope the fix.

How auth breaks in AI-built apps

01
OAuth redirects to localhost
The redirect URL was set to localhost:3000 in development and was never updated. It works locally; every production login fails.
02
Sessions expire silently
The access token expires and the app doesn't refresh it. Users hit a wall — sometimes a blank screen, sometimes a silent 401. They churn instead of reporting it.
03
Password reset goes to the wrong URL
The reset email links back to the builder's preview URL, not your production domain. Every reset email is broken.
04
Auth state doesn't survive page reload
onAuthStateChange isn't wired up. Refreshing the page logs the user out.
05
RLS not connected to auth
The auth is working but Supabase RLS isn't checking auth.uid(). Users are authenticated but RLS still leaks their neighbours' data.
06
Social login works but email doesn't
Google OAuth was tested; email+password was not. The sign-up confirmation email is broken or the confirmation redirect is wrong.

The four ways AI-generated auth breaks in production

Almost every auth regression we triage on rescue calls lands in one of four buckets. The symptoms look different in the browser, but the underlying misconfiguration is usually predictable.

1. Session cookies misconfigured

Supabase, Clerk, and Auth.js all rely on HTTP-only cookies to persist a session across requests. AI-generated code commonly either forgets sameSite, forgets to scope the cookie domain to a shared parent for multi-subdomain apps, or ships secure: false into a production HTTPS environment. The user sees: login appears to succeed, then the next page loads as logged-out. We audit the Set-Cookie header on the login response and compare it against what the server actually reads back on subsequent requests.

2. OAuth callback URL drift

The Google Cloud, GitHub, or Apple OAuth client has an allow-list of redirect URIs. AI builders scaffold with a preview URL (localhost:3000, a StackBlitz URL, a Vercel preview domain) and never prompt you to add the production domain. Every production login 302s to an error page. We enumerate every provider’s allow-list, add the production callback paths (/auth/callback, /api/auth/callback/google, and the Supabase /auth/v1/callback equivalents), and verify with an incognito login.

3. Supabase RLS disabled or mis-scoped

Auth without Row Level Security means every logged-in user can read every row. Lovable and Bolt scaffolds regularly ship with RLS disabled or with policies set to using (true), which is equivalent to no policy at all. We enable RLS on every table, add per-user policies that reference auth.uid() = user_id, and test with two accounts in separate incognito sessions. See Supabase RLS blocking insert for the opposite failure mode.

4. Session expiry too short, refresh never wired

Access tokens expire on a one-hour clock by default. If the client isn’t configured with autoRefreshToken: true and an onAuthStateChange listener, the next silent request returns 401 and the app either flashes a blank screen or kicks the user to /login. We wire the refresh loop, add a middleware that calls getUser() (not getSession()) on protected routes, and verify that a tab left open for two hours still shows a logged-in state after refresh.

How we audit

On a diagnostic call we reproduce every documented failure in an incognito window against your production domain. We read the Network tab line by line: the login POST, the Set-Cookie response, the next authenticated request, the RLS query, and the logout call. We compare what the server sends against what the browser stores and what the server reads back. Most auth rescues are fixable inside a single 48-hour engagement once the exact mis-wiring is on paper.

What you get

A written audit identifying every broken redirect, cookie, policy, and refresh gap. A fixed-price scope with a ship date. For most apps the fix itself is 1–3 days of focused work with no rewrites, no data migrations, and no forced re-registration for existing users. Related deep-dives: users can’t log in after deploy, OAuth callback URL not working in production, and session expires immediately.

FAQ
How do I know if my auth is broken?
Log in as a new user on your production domain. Try: logging in with Google, logging in with email+password, resetting your password, and refreshing the page after login. If any of these fail, your auth is broken.
Why does auth work locally but not in production?
Almost always the OAuth redirect URL. The provider (Google, GitHub, etc.) has an allowed redirect list. If production isn't on that list, every login fails with a redirect_uri_mismatch error.
Can you fix auth without rewriting the whole app?
Yes. In most AI-built apps, auth is isolated enough that we fix it without touching other logic. Typical fix is 1–3 days.
My users are already signed up. Will fixing auth log them out?
No. We work on the session handling and OAuth config without touching the user records. Existing users keep their accounts.
What providers do you support?
Any Supabase-compatible provider: Google, GitHub, Apple, Microsoft, email/password, magic link, and phone OTP. We also support custom JWT auth if you're not using Supabase.
Next step

Free auth audit in 48 hours

We reproduce the failure, identify every broken redirect and session gap, and send you a written report. Free, no commitment.

Book free diagnostic →