Password authentication exposes a public decision point: a client submits a claimed identity and a secret, then the server accepts or rejects the pair. Attackers can automate that decision point at a scale no human user can match.

A simple request limit helps, but authentication traffic has unusual constraints. A limit tied only to an IP address can punish thousands of legitimate users behind one gateway. A limit tied only to an account lets an attacker deliberately block a victim from signing in. A permanent account lock can turn a guessing defense into a denial-of-service primitive.

A stronger design treats throttling as a control system. It measures repeated failures across several dimensions, raises the cost of continued guessing, keeps recovery possible, and records enough evidence for operators to detect abuse.

Start with the attacker’s budget

An online guessing attack succeeds only if the service permits enough trials. Throttling reduces the number of guesses an attacker can submit during a useful period.

Suppose an endpoint accepts one failed attempt every 200 milliseconds. A single worker can submit roughly 18,000 attempts per hour. Adding more workers or source addresses can increase that total unless the service also measures activity around the target account.

Now suppose repeated failures for one account trigger increasing delays:

failures in recent window    next permitted attempt
1-3                          immediate
4                            after 2 seconds
5                            after 4 seconds
6                            after 8 seconds
7+                           after 30 seconds

The exact values depend on the service, user population, and threat model. The important property is that repeated failure becomes progressively expensive without creating an indefinite lock.

A throttle is not a substitute for strong password hashing, multi-factor authentication, breached-password screening, or secure session handling. It limits online trial volume; those other controls address different parts of the authentication system.

Measure more than one dimension

No single rate-limit key represents all authentication abuse.

An IP-based counter is useful for a noisy source repeatedly attacking many accounts. It is weak against distributed traffic and can cause collateral damage when many people share a corporate proxy, carrier network, university gateway, or privacy relay.

An account-based counter follows attacks against one identity even as source addresses change. Used as a hard lock, however, it gives an attacker a direct way to deny access to a known account.

A practical design can combine signals such as:

  • failures per account identifier;
  • failures per source network or address;
  • distinct accounts attempted from one source;
  • total authentication volume at the service edge;
  • device or session signals when they are trustworthy and privacy-appropriate.

Each signal answers a different question. The enforcement decision can use the strongest applicable restriction rather than trusting one counter to describe the whole event.

For example, a source attempting hundreds of distinct accounts may receive aggressive throttling even if each account has only one failure. An account receiving failures from many unrelated sources may receive a moderate account-level delay without being permanently disabled.

Prefer delay over attacker-controlled lockout

A hard rule such as “five failures disables the account until support restores it” is easy to understand and easy to abuse. Anyone who knows a valid username can intentionally submit five bad passwords.

Progressive delay usually has a safer failure mode. A user who mistypes a password waits briefly. A bot that continues guessing pays the delay repeatedly.

The delay should be enforced by server-side state. Sleeping inside an application worker for 30 seconds is usually wasteful because it holds resources while doing no useful work. Instead, record the next permitted attempt time and reject premature requests quickly.

A conceptual record might contain:

key: auth-account:8f3c...
failure_count: 6
window_started_at: 2026-09-12T00:40:00Z
next_allowed_at: 2026-09-12T00:41:08Z
expires_at: 2026-09-12T01:10:00Z

The account key can be a stable internal identifier when one is available. If the submitted identifier is not yet mapped to an account, normalize it consistently before using it as a counter key.

Do not put raw passwords, session tokens, recovery codes, or other secrets into rate-limit keys or logs.

Keep responses resistant to account enumeration

Throttling can accidentally reveal whether an account exists.

Consider these responses:

unknown account: 401 Invalid credentials
known throttled account: 429 Too many attempts; retry in 30 seconds

An observer can test identifiers and distinguish registered accounts from unregistered ones. That information can support targeted credential attacks.

Public responses should avoid unnecessary differences based on account existence. Status codes, response bodies, timing, and headers all form part of the observable behavior.

This does not mean every internal state must be identical. The service may maintain richer counters for real accounts while presenting a uniform external authentication response. The design goal is to avoid turning internal account state into a reliable discovery oracle.

Reset counters with care

A successful authentication is useful evidence, but resetting every related counter can create a bypass.

Imagine an attacker controls one valid account and sends guesses against many victims from the same source. If any successful sign-in clears the entire source counter, the attacker can periodically authenticate to the controlled account and erase evidence of the broader attack.

Reset only the state that the successful proof justifies.

For example:

  • a successful sign-in can clear or reduce failure state for that account;
  • source-wide abuse counters can continue on their own window;
  • service-wide protection should remain independent;
  • risk signals associated with many targeted accounts should not vanish because one credential was valid.

Counter expiration is also important. Old failures should decay so occasional mistakes do not accumulate forever. Fixed windows, sliding windows, token buckets, and exponential backoff can all work when their semantics are understood and tested.

Make distributed enforcement atomic

Authentication services often run on many application instances. A counter stored only in process memory can be bypassed by requests that land on different instances.

Shared state must also handle concurrent updates correctly. This pattern is unsafe:

count = read(key)
if count < limit:
    write(key, count + 1)
    allow()

Two requests can read the same value before either writes, so both may pass a boundary intended for one request.

Use a storage operation that updates and checks the relevant state atomically. Depending on the data store, that can be an atomic increment with expiration, a transaction, a server-side script, or a purpose-built rate-limiting primitive.

Failure behavior deserves an explicit policy. If the shared limiter is unavailable, blindly allowing unlimited attempts removes a security control at the moment visibility may also be degraded. Blindly rejecting every sign-in can cause a broad outage. Services can use bounded local fallback limits, circuit breakers, redundant limiter infrastructure, or risk-based fail modes according to their availability requirements.

Put limits at more than one layer

Edge infrastructure can cheaply absorb obvious floods before requests consume application resources. Application-level enforcement has richer identity context.

These layers complement each other:

internet
   |
   v
edge request limit
   |
   v
authentication service
   |
   +--> source behavior counter
   |
   +--> account failure counter
   |
   +--> risk signals
   |
   v
credential verification

An edge limit can cap raw request volume by source or network. The authentication service can then apply account-aware controls that the edge cannot safely infer.

Credential verification itself may be intentionally expensive because secure password hashing consumes CPU and memory. Rejecting clearly over-limit requests before running the password hash protects that capacity. Still, the external behavior must not expose account existence through obvious timing differences.

Separate password failures from other events

Not every authentication error should consume the same budget.

Malformed requests, expired one-time codes, invalid passwords, unavailable identity providers, internal timeouts, and policy denials represent different conditions. Treating every error as a password failure can lock legitimate users into delays during an infrastructure incident.

Define which outcomes increment which counters. Keep that mapping close to the authentication state machine and test it explicitly.

A useful rule is to increment a credential-failure counter only after the request reaches the relevant credential check and the presented proof is invalid. Separate abuse counters can still track malformed or high-volume traffic.

Return useful retry information cautiously

For machine-facing APIs, a retry interval can help well-behaved clients back off. For public sign-in endpoints, detailed retry state may expose internal enforcement data.

If a Retry-After header is appropriate, make sure it matches actual server behavior. A client told to retry after 10 seconds should not encounter a hidden 60-second delay unless another documented limit applies.

Client-side countdowns improve usability but do not enforce security. Attackers control their clients. The server remains authoritative for every retry decision.

Observe the system, not secret material

A throttle that cannot be observed is difficult to tune.

Useful metrics include:

  • rejected attempts by enforcement dimension;
  • distribution of delay durations;
  • distinct accounts targeted per source;
  • distinct sources targeting one account;
  • successful sign-ins following throttling;
  • limiter storage latency and error rate;
  • support reports associated with false positives.

Logs should identify the applied policy and a safe correlation key without recording credentials. If identifiers are sensitive, use an approved pseudonymous representation that operators can correlate for the required retention period.

Alerting should focus on patterns that indicate a campaign, not every individual failed password. Large fan-out from a source and large fan-in toward an account are especially useful shapes to monitor.

Test adversarial and ordinary traffic

A throttle needs tests beyond “the sixth request returns an error.”

Exercise cases such as:

  1. one user mistypes a password several times and then succeeds;
  2. one source attempts many different accounts;
  3. many sources attempt one account;
  4. many legitimate users share one source address;
  5. concurrent requests arrive at the limit boundary;
  6. the shared counter store becomes slow or unavailable;
  7. counters expire and traffic resumes;
  8. a successful sign-in resets only intended state;
  9. unknown and known account responses remain suitably similar;
  10. application instances observe consistent enforcement.

Load tests matter because a limiter that becomes a bottleneck during attack traffic can amplify the incident it was meant to contain.

A compact implementation model

A useful mental model is to separate observation, decision, and credential verification:

request
  |
  v
normalize submitted identifier
  |
  v
read/update abuse signals atomically
  |
  v
over limit? ---- yes ----> return bounded generic response
  |
  no
  |
  v
verify credential
  |
  +---- invalid ----> update failure state
  |
  +---- valid ------> reduce justified account state
  |
  v
continue authentication flow

This separation makes policy easier to review. It also reduces the chance that a successful credential accidentally clears unrelated attack evidence.

Design for bounded damage

Authentication throttling has two competing failure modes. Weak enforcement permits high-volume guessing. Overly rigid enforcement lets hostile traffic deny access to legitimate users.

The strongest designs avoid treating those goals as a binary choice. They combine multiple counters, progressive delays, atomic distributed state, bounded expiration, uniform public responses, and operational telemetry.

The result is not an impenetrable login endpoint. It is an endpoint that gives automated guessing a constrained budget while preserving a practical path for legitimate users to recover from mistakes and continue signing in.