Rate Limiting, Quotas & Abuse Protection · Where and What to Enforce

Application-Level Limits

Business-aware limits implemented in your services.

Application limits encode domain rules: one OTP per phone per 60 s and 5 per hour, 10 failed logins per account per 15 min, 3 password resets per email per day, N exports per tenant per day, invitations per hour. Implement them as reusable middleware/decorators/dependencies with clear keys, return Problem Details 429 with Retry-After, and log limit hits as security signals.

Common business limits

Action Typical limit Key
Send OTP / SMS 1/min, 5/hour phone number + IP
Failed logins 5–10 per 15 min account + IP
Password reset 3/day email
Exports 10/day tenant
Invitations 50/hour account
def limit(name: str, capacity: int, per_seconds: int, key_fn):
    async def dep(request: Request):
        key = f"{name}:{await key_fn(request)}"
        ok, _, retry = token_bucket(key, capacity, capacity / per_seconds)
        if not ok:
            raise HTTPException(429, "Too many attempts", headers={"Retry-After": str(retry)})
    return Depends(dep)

@router.post("/otp", dependencies=[limit("otp-phone", 5, 3600, lambda r: phone_from_body(r))])
async def send_otp(body: OtpIn): ...

Common pitfalls

  • Counting successful logins toward lockout limits.
  • Limits keyed only on IP for OTP (SMS pumping fraud).
  • Silent limits that look like bugs to users.

Key points

  • Encode domain rules
  • Reusable middleware
  • Log limit hits as signals

Further reading: OWASP Authentication Cheat Sheet

Practice questions

What is SMS pumping fraud and how do rate limits help?

Answer

Attackers trigger OTP/SMS sends to premium numbers they profit from; per-phone, per-IP and per-country limits (plus anomaly detection) cap the damage.

Should successful logins count toward failed-login limits?

Answer

No — count failures, and consider resetting counters on success, so legitimate users aren't locked out.

Open in the app to mark lessons complete, take notes and track your progress.