Rate Limiting: The Cheap Control That Stops Expensive Abuse
Brute force, scraping, credential stuffing and cost-draining abuse all rely on volume. Rate limiting caps the volume β and it's one of the highest-return controls you can add.
A surprising number of serious attacks share one requirement: they need to make many requests. Brute-forcing a password means trying thousands of guesses. Credential stuffing means testing stolen username-password pairs at scale. Scraping means pulling data one page at a time, endlessly. Denial of service means overwhelming a system with traffic. Even runaway costs β an abused API racking up a huge bill β depend on volume. Rate limiting attacks all of these at once by capping how many requests a client can make, and it is among the cheapest, highest-return controls available.
The insight is that limiting volume neutralizes an entire family of threats that only work when volume is unlimited.
What rate limiting does
At its simplest, rate limiting counts requests from a given source over a window of time and rejects or delays those beyond a threshold. Ten login attempts per minute is plenty for a real user and useless for a brute-force tool. A few hundred API calls per minute serves a legitimate integration and starves a scraper trying to pull your entire dataset. By making high-volume abuse impossible or painfully slow, rate limiting removes the very thing the attack depends on β without inconveniencing normal use, which almost never approaches the limits.
It also protects against non-malicious harm: a buggy client stuck in a loop, or a sudden traffic spike, is throttled before it takes the system down or drains a budget.
Designing limits that work
Effective rate limiting is thoughtful about what it counts and how. Limit by the right key β per user, per IP, per API key, or a combination β recognizing that IP-based limits alone are weak against distributed attacks and shared addresses. Apply stricter limits to sensitive, expensive or abusable endpoints (login, password reset, search, anything costly) than to cheap static ones. Return clear signals when a limit is hit, so legitimate clients can back off gracefully rather than hammering harder. And consider graduated responses: slowing down before hard-blocking, or requiring an additional challenge after suspicious volume.
For login specifically, pairing rate limits with account-lockout thresholds and monitoring turns brute force from a real threat into a caught and blocked one.
Beyond simple counting
More sophisticated abuse defense builds on the same foundation. Detecting patterns β one client suddenly requesting far more than its history, many clients testing one endpoint in concert, traffic that looks automated rather than human β catches distributed and adaptive abuse that fixed per-source limits miss. Quotas over longer windows cap total cost and data exposure even when per-minute traffic looks normal. And placing these controls at the edge, before requests reach expensive backend systems, means the abuse is absorbed cheaply rather than after it has already consumed resources.
Rate limiting will never be the flashiest line on a security architecture, but few controls prevent so many different attacks for so little effort. Cap the volume, protect the sensitive and expensive endpoints hardest, signal clearly, watch for patterns, and enforce at the edge β and brute force, stuffing, scraping and cost abuse all run into the same simple wall.
The common algorithms
Several algorithms implement rate limits, each with trade-offs. A fixed window counts requests per calendar minute or hour; it is simple but allows bursts at window boundaries, where a client can send a full quota at the end of one window and another at the start of the next. Sliding windows smooth this out by considering the most recent period continuously. The token bucket refills tokens at a steady rate and lets clients spend them in bursts up to the bucket size, which suits real traffic well. The leaky bucket processes requests at a constant rate, queuing or dropping the excess, which protects fragile backends.
Where to enforce limits
Limits can be applied at several layers, and mature systems use more than one. The network edge β a content delivery network, web application firewall or load balancer β can absorb floods before they reach your servers. An API gateway can apply limits per key or per customer plan. The application itself knows about users, accounts and business actions, so it can enforce rules such as "five password reset emails per account per hour" that the outer layers cannot express. Enforcing coarse limits at the edge and precise limits in the application gives both protection and accuracy.
Counting across many servers
When an application runs on many instances, each one counting requests separately lets a client multiply its allowance by spreading requests across them. Shared counters in a fast central store solve this, at the cost of an extra network call per request. For very high traffic, approximate approaches β local counters synchronized periodically, or limits divided across instances β trade a little precision for speed. Decide what happens if the counter store is unavailable: failing open keeps the service running but removes protection, while failing closed blocks legitimate users, so the choice should depend on the endpoint's sensitivity.
Choosing what to count by
IP addresses are the easiest key and the weakest. Many legitimate users can share one address behind corporate networks or mobile carriers, while attackers rotate through thousands of addresses using botnets and proxy services. With IPv6, a single user may control a huge range of addresses, so limits should apply to address blocks rather than individual addresses. Authenticated identities and API keys are much stronger keys where available. Combining keys β per account, per address range and per endpoint β makes limits harder to evade without punishing innocent users who share infrastructure.
Responding the right way
When a client exceeds a limit, the standard response is HTTP status 429, "Too Many Requests," ideally with a Retry-After header indicating when to try again. Well-behaved clients and libraries use this to back off automatically. Include the current limits and remaining allowance in response headers for API consumers, so that integrations can pace themselves. Avoid revealing more than necessary on sensitive endpoints, though: a login form should not tell an attacker exactly how many attempts remain before a block.
Protecting login and password reset
Authentication endpoints deserve layered protection. Limit attempts both per account and per source, so that attackers cannot target one account from many addresses or many accounts from one address. Be careful with hard account lockouts, which let anyone lock out a legitimate user by deliberately failing logins; progressive delays or additional challenges are often safer. Limit password reset requests and one-time code attempts, since a short numeric code can be guessed if attempts are unlimited. Multi-factor authentication and checks against known breached passwords reduce the value of any guesses that slip through.
Credential stuffing
Credential stuffing uses username and password pairs leaked from other sites, testing them at scale in the hope that people reused passwords. The traffic often arrives from many addresses at a low rate per address, deliberately designed to stay under simple limits. Signals that help include an unusually high proportion of failed logins across the whole service, many different accounts attempted from the same device characteristics and logins for accounts that do not exist. Responding at the level of the whole service β tightening challenges when global failure rates spike β catches attacks that per-source limits miss.
Scraping and data harvesting
Scrapers want data, and they adapt to simple limits by slowing down and spreading out. Make bulk extraction expensive: cap page sizes and result counts, require authentication for detailed data, apply daily quotas per account and watch for clients that systematically walk through identifiers or search results. Accounts created in bulk to multiply quotas are a common pattern, so limits on account creation matter too. Some scraping is legitimate, such as search engine crawlers that follow published rules, so distinguish well-behaved crawlers from aggressive harvesting.
Cost-based limits for AI and expensive endpoints
Request counts are a poor measure for endpoints whose cost varies widely, such as AI features where one request may process a few words or an entire book. Limit by the resource consumed instead β tokens, processing seconds or estimated cost β per user and per organization, over both short and long windows. Set hard budget caps for free tiers and trials, which attract automated abuse, and alert when an account's consumption jumps far above its history. A leaked API key without cost limits can generate an enormous bill in a single night.
Fairness for legitimate heavy users
Limits that are too tight drive away good customers. Offer higher limits on paid plans or by agreement, allow short bursts above the sustained rate, and provide bulk or batch interfaces for clients that genuinely need large volumes, which are cheaper to serve than many individual calls. Publish your limits so integrators can design around them, and give customers a way to request increases. A clear, documented policy turns rate limiting from a source of frustration into part of a reliable service.
Rolling out and tuning limits
Introducing limits on a live system risks blocking legitimate traffic you did not know about. Start in observation mode: compute what would have been limited and log it without blocking. Review which clients would have been affected, adjust thresholds and add exceptions where justified, then switch to enforcement gradually, starting with the most abused endpoints. Revisit limits as usage grows, because yesterday's generous threshold can become today's bottleneck.
Monitoring and response
Rate limiting produces valuable signals. Track how often limits are hit, by which clients and on which endpoints. A sudden rise in limited requests may indicate an attack in progress, a buggy client release or a limit that has become too tight. Feed these events into security monitoring, block or challenge sources that repeatedly hit limits on sensitive endpoints, and review the patterns after each incident.
A quick checklist
Every public endpoint has a limit. Login, reset, sign-up, search and expensive operations have stricter ones. Limits use strong keys such as accounts and API keys, with address-range limits as a backstop. Counters are shared across instances. Clients receive 429 responses with retry guidance. AI and other variable-cost features are limited by consumption. New limits are tested in observation mode, and limit events are monitored. With these in place, volume-based attacks lose most of their power.
Run AI on your own terms
AXTO gives you world-class AI apps and self-hosted editions β on your own keys, your own data.