Every account takeover starts in your auth logs

Account takeover is rarely sophisticated. It is thousands of stolen username-password pairs replayed against your sign-in endpoint until one works — and every one of those attempts is written to your Supabase auth logs before the successful one happens. The signal is there. The question is whether anyone is reading it.

What attacks on Supabase Auth actually look like

Credential stuffing

Pairs leaked from someone else's breach, replayed against your app. The fingerprint is a high volume of invalid_grant failures concentrated on a small number of real account emails, arriving from many addresses across a couple of hosting ASNs. The attacker does not need to guess — they are checking which of the leaked passwords your users reused.

Password spraying

The inverse shape: one or two common passwords tried against a great many accounts, slowly enough to stay under per-account lockouts. Per-account thresholds never fire. Only a view across accounts catches it.

The successful login you did not notice

The dangerous event is not the failures — it is the single session_created that follows them from the same address. Failures alone are noise. Failures followed by a success on the same targeted account are an account takeover in progress, and that correlation is what deserves a page at 3am.

Signals worth alerting on

What to do about it

Turn on CAPTCHA for the password grant in your Supabase Auth settings — it raises the cost of automation sharply for very little user friction. Require MFA for admin accounts. And when an incident does fire, force a password reset on the specific accounts that were targeted rather than on everyone, which is both more proportionate and more likely to actually get done.

How Defencecore catches it

Defencecore reads your Supabase auth logs and correlates events rather than counting them one at a time. Related failures group into a single incident keyed by rule and entity — the targeted account, the source address — so a distributed attempt appears as one finding with 400 events attached, not 400 alerts. Each incident carries the timeline, the accounts involved, and the raw log lines behind it, and the status moves through open, acknowledged, and resolved as you work it.

Frequently asked questions

Does Supabase rate limiting already stop credential stuffing?
It blunts it. Supabase applies rate limits to the password grant, and a naive attack from one address gets throttled. A distributed attempt rotating through dozens of addresses stays under the per-address limit while still testing thousands of passwords, and rate limiting alone will not tell you it happened.
What does a failed Supabase sign-in look like in the logs?
GoTrue writes auth events as JSON lines. A failed password grant carries an invalid_grant error with the attempted email and the source IP; the useful signal is the rate and spread — many failures across few accounts is credential stuffing, few failures across many accounts is password spraying.
Should I alert on a successful login from a new country?
As a low-severity signal, yes — but expect false positives from travel and VPNs. It is most valuable in combination: a new geography for an admin account, shortly after a burst of failures against that same account, is a much stronger signal than either event alone.
How is OAuth sign-in different to monitor?
OAuth moves the credential check to the provider, so you stop seeing password failures and start caring about different things: which providers are enabled, whether an account can be taken over by signing in with a different provider on the same email address, and sudden changes in the mix of providers used.