Rate-limit your login endpoint

Not the whole site. The login, password-reset, and MFA endpoints specifically — by account, not just by IP.

· LoginWith team

Most sites rate-limit the whole API uniformly at the edge. That’s fine for preventing DDoS, useless for stopping credential stuffing. Auth endpoints need their own, sharper controls.

Why IP-based limits fail

Credential stuffing attacks don’t come from a single IP. They come from botnets of residential proxies — 10,000 compromised home routers in 50 countries, each making one or two attempts per hour. A 100-request-per-minute IP limit never triggers.

What triggers is the attacker’s pattern: one account, many attempts. That’s the signal to catch.

The design

Per-account rate limit on login:

  • 5 failed attempts in 5 minutes → lock the account for 15 minutes
  • 5 more failed attempts after unlock → lock for 1 hour
  • 5 more → lock for 24 hours, notify the account owner via email

The escalation matters. A one-time lockout is easily brute-forced around by a patient attacker. Exponential cooldowns with email notification turn a credential stuffing attack into a very visible, very slow denial-of-service that admins can investigate.

Per-IP rate limit as a secondary signal:

  • 100 login attempts per IP per minute → short block
  • This catches dumber attacks from single-IP bots

Per-account rate limit on password reset and MFA:

  • Same pattern — 5 attempts in 5 minutes, then escalating cooldowns
  • Password reset brute force is a real attack (guessing short reset tokens)
  • MFA brute force is what happens after a password compromise — it’s your last line of defense

Implementation

In Redis or Postgres, keep a counter per (account_id, endpoint, time_bucket). On each attempt, increment. If the counter exceeds the threshold, reject with a 429 and a Retry-After header. Reset or decay the counter over the window.

Capture the failed attempts in your audit log, not just in the rate-limiter state. You want to be able to answer “how many failed attempts did account X have last week?” in 30 seconds.

Captcha as a fallback

For public-facing consumer apps, add a Captcha on the 3rd or 4th failed attempt from a given account or IP. It’s annoying, but so is a successful account takeover. Users who got their own password wrong once won’t see it; attackers will see it constantly.

What not to do

Don’t rate-limit so aggressively that a legitimate user who typos three times gets locked out for an hour. 5 attempts in 5 minutes with a 15-minute cooldown is the sweet spot for most consumer and B2B apps. Tune it to your user base.

Want auth that just works?

Get started with LoginWith