Run this test before you read anything else
It takes two minutes and it answers the most important question on this page.
Create a second account on your app. Log in as that user.
Find a URL or an API call that includes an ID — an order, a document, a profile.
Change that ID to one belonging to your first account.
If the data loads, anyone who signs up can already read everyone else's data.
There is no error. No log entry. No alert. The application behaves exactly as designed, which is why this survives to production in a large share of AI-built apps and is usually found by someone who wasn't looking for it.
If that test loaded something it shouldn't have, stop reading and get help today.
If it didn't — here's what's probably going on instead.
Auth looks like one feature. It's five.
That's the whole reason this breaks.
Signing in is one problem. Staying signed in is another. Proving who you are across different environments is a third. Getting back in when you're locked out is a fourth. Being stopped from doing things that aren't yours is a fifth.
AI builders generate the first one well, because it's the one you test while building. You sign in, it works, you move on.
The other four only matter once there's a second user, a production domain, or someone who forgot their password — all of which arrive after launch, and none of which existed while the code was being written.
Which is why auth problems are almost never in the login screen. They're in what happens next.
So what's actually failing?
What you see, and what's usually behind it
What you see | What's usually wrong |
Login succeeds, bounces back to login | Production domain missing from the redirect URL list |
Works for you, not for new users | A role or permission check that only passes for older accounts |
Logged out randomly | Session refresh not handled, or token expiry set shorter than intended |
Never logged out | No session expiry at all — a token issued once works forever |
OAuth shows a provider error page | Callback URL or client credentials scoped to development |
Password reset email never arrives | Email provider unconfigured, or sending domain not authenticated |
Reset link works more than once | Token not invalidated after use or after a password change |
Admin page loads for a normal user | Authorization enforced in the interface, not on the server |
Flickering redirect on page load | Auth state read before the session has finished loading |
Anyone can sign up as anyone | No email verification, so addresses aren't proven |
API returns data the UI hides | The route has no authorization check at all |
Users see each other's data | Missing or permissive row-level security |
The eight causes underneath
Redirect URLs pointing at the preview domain. In Supabase that's Authentication → URL Configuration, both the Site URL and the Redirect URLs list. In Google Cloud Console it's the OAuth client's authorised redirect URIs. In Clerk, Auth0 or Firebase it's the allowed callback list. Login itself works; the session is discarded on the way back, which is what produces the loop.
Authorization enforced in the browser. The interface hides the admin button. The API still answers the request. Anyone who opens the network tab, or simply guesses the endpoint, can call it directly. This is the most common serious finding on this page and it's invisible from the front end.
Sessions that never expire. A token issued once works indefinitely. A laptop left in a café stays logged in, and a user you've removed isn't actually removed until their token is revoked — which nothing does.
Password reset with a reusable token. The link still works after it's been used, or after the password has changed again. Anyone with access to an old email can get back in months later.
No email verification. Accounts created against addresses the person doesn't control. Matters most when email is the identity, or when you're sending anything sensitive to it.
OAuth working locally, failing live. Google, GitHub, Apple — all fail the same way. Callback URLs, allowed domains and client IDs configured for development only, so users see a provider error page rather than your application.
Roles that exist and aren't checked. A role or is_admin field on the user record, and nothing consults it before allowing the action. The data model is right and the enforcement was never written.
Auth state read before it's ready. The app checks whether someone is signed in before the session has loaded, decides they aren't, and redirects. Produces flickering redirects, intermittent logouts, and bug reports that nobody can reproduce.
Three of these you can check in about ten minutes.
Three checks worth running
We'd rather you didn't pay us for a four-minute fix.
If users are stuck in a login loop Open Supabase → Authentication → URL Configuration. Your production domain needs to be in both the Site URL and the Redirect URLs list. If only the preview or localhost domain is there, that's your loop. Same idea in Clerk, Auth0 or Google Cloud Console — find the allowed callback list and check your real domain is on it.
Test your admin route directly Log in as an ordinary user and navigate straight to an admin URL by typing it. If the page loads, your authorization is cosmetic. If the page blocks you but the underlying API still returns data, it's cosmetic in a way that's harder to see and just as serious.
Use a password reset link twice Request a reset, use the link, change your password. Now open the same link again. If it works, your tokens aren't being invalidated — which means an old email is a permanent way in.
If any of those came back badly, or none of them explains it —
When to stop and get help
The cross-account test loaded data. This is the one with actual exposure. Nothing in your logs will show it, and it won't announce itself.
You've been on the same auth failure for more than two hours. Auth problems are configuration more often than code, and configuration problems are found by reading, not by trying.
Users are locked out right now. Every hour has a cost, and experimenting on a live auth system tends to make things worse before better.
You're not sure what your permission model actually is. If nobody can state who should be allowed to do what, the code can't be checked against it — and that's the thing an outside reader establishes first.
Here's how we approach it.
We trace the whole flow, not the login screen
An engineer follows a user through every stage: sign-in, session creation, refresh, authorization on each protected action, and recovery when they're locked out. Each stage is tested from an unprivileged account rather than assumed from a dashboard.
That last part is where most of the findings come from. A settings page showing that protection is enabled tells you the feature is switched on. It doesn't tell you the rule underneath does anything — and those are very different facts.
You get login working across environments, sessions that behave predictably, authorization enforced where a browser can't remove it, and recovery flows that can't be replayed. Plus a written note on what was wrong, so it doesn't return next time someone prompts a change.
What we won't do
Fix the login screen and leave the session handling. That's most of the problem.
Enforce permissions in the interface only. It looks fixed and isn't.
Replace your auth provider unless there's a real reason. Supabase, Clerk, Firebase and Auth0 are all fine; the configuration usually isn't.
One thing worth saying about what this costs.
Auth is cheap to fix and expensive to leave
Most of what's on this page is hours of work, not weeks. Redirect lists, session config, token invalidation, moving a permission check from the client to the server — none of it is hard once someone has read the flow.
What it costs to leave is a different shape. A cross-account leak isn't a bug report, it's a conversation with your customers. An admin endpoint anyone can call isn't downtime, it's whatever the person who found it decided to do. And an enterprise customer's security questionnaire will ask about every item in the list above.
The asymmetry is the point: small to fix now, and not the kind of problem that stays small.
How it runs
01 — Audit. You send the repository. An engineer reads the full auth flow and comes back within 48 hours with what's broken and what's exposed. Free.
02 — Triage. Findings separated by consequence — what someone could exploit today, versus what's inconvenient.
03 — Contain. Anything exploitable right now gets closed first, before anything else is touched.
04 — Fix. Redirects, sessions, tokens, verification and role checks corrected at source.
05 — Enforce. Authorization moved server-side, where a browser can't remove it.
06 — Verify. Tested from a second account and a logged-out session. Not assumed from settings.
07 — Handover. What was wrong, what changed, and how to add roles later without reopening any of it.
Questions
Supabase Auth, Clerk, Firebase, Auth0, NextAuth, or custom? All of them. The failure classes are identical wherever auth is configured rather than written from scratch.
Login works for me but not for some users. Usually session timing, or a role check that only passes for accounts created before a schema change. Both are quick to confirm once someone reads the flow.
Do we need to rebuild auth or switch providers? Rarely. The provider is normally fine. The configuration and the authorization layer are where the problems sit, and both are fixable in place.
Can you add roles and permissions? Yes, and this is the right moment to do it — the checks have to live somewhere the client can't reach, and retrofitting that later is harder than doing it during a fix.
Can you produce something for a customer's security questionnaire? Yes. Auth and access control are most of what those questionnaires ask about, and we can supply findings plus a remediation record.
Will you sign an NDA? Yes, mutual, before you send anything. One senior engineer reads your code, never used for training, access removed after delivery.
Users are locked out right now. Tick the box on the form. Live incidents jump the queue.
Send us the repository
You'll get the auth configuration problems, the authorization gaps, the recovery flows that can be replayed — and whichever of those someone could use today, named first.
Read access is enough. Mutual NDA first if you'd prefer.
Also broken?
Supabase · Security audit · Database and multi-tenancy · Works in preview, breaks after deploy · Payments · Lovable