Match each limit to an abuse case

A transfer-create limit, password-guess limit, and report-export budget protect different resources. A single global counter makes their behavior hard to explain. List each key, time window, cost, and reset rule before testing. Check whether parallel requests pass before the counter updates. Check whether failed requests consume a quota and whether that matches your policy. Keep the user response clear: state when to retry without revealing another account’s activity.

Test cases and proof

Use test accounts and test data
CaseExpected resultProof to keep
One account rotates IPsAccount limit still appliesCounter and response
Two users share IPSeparate account quotas; shared capacity rules still applyPer-user counters
Token refresh after limitRefresh does not reset account quotaRequest timeline

Synthetic example

Ten failed OTP attempts from one account should remain ten attempts when the account changes IP address. Two customers behind one office gateway should still have separate account quotas. Record which key each rule uses and what happens on token refresh.

Evidence to keep

Use a traffic plan that stays below provider safety limits. Record the counter key selected for each request, the action cost, response code, and reset time. Run a small parallel burst only in staging. The aim is to prove that requests cannot outrun the counter update, not to measure maximum throughput. Do not use real customer accounts for the test.

Do not confuse abuse and capacity

A request budget protects server work; an account guess limit protects an identity. The same threshold and counter key should not serve both. A shared-IP rule can help with broad traffic spikes, but a strict account lock based on IP can punish unrelated customers. Measure normal traffic in the test environment before setting a threshold. For failures, record whether the counter increments on rejected calls and whether a retry-after hint is accurate. A 429 that resets on token refresh does not stop one account from repeating the action.

Related reading

Why these checks matter

OWASP API4 describes harm from unbounded API resource use, including CPU, storage, and network costs. The authorization guide explains why each action also needs a clear caller identity. A rate-limit key is an implementation choice based on the harm: the account matters for guessing, while request cost matters for heavy export work.

Separate login guesses from authenticated quotas

Synthetic login rule: at most ten failed verification attempts for one normalized account identifier in a 15-minute test window. Send five failures for A from IP-1 and five from IP-2. Attempt 11 is slowed under the policy. A successful token refresh is not part of this login fixture: a caller making failed unauthenticated guesses has no new session token to rotate. Test another email spelling under the application’s normalization rule without merging unrelated addresses.

Now use a separate authenticated export rule: two jobs per user per minute and one active job per tenant. Customer A refreshes a token after creating two jobs. A still cannot create a third within the window. Customer B on the same IP retains B’s user quota, but may be blocked by the clearly named tenant-capacity rule. This distinction makes expected fairness precise.

Check concurrent counters and delivery budgets

Start with one remaining slot and send two requests at the same time from different app instances. The atomic decision should allow at most one new export. Record the chosen key, window, cost, and decision from both instances. Test counter-store outage under the stated fail-open or fail-closed rule; do not infer safety from a 429 on one healthy node.

Code-send budgets protect SMS cost and customer disruption. Verification-attempt budgets protect guessing. Resend must not reset the latter. A shared-IP limit can still apply above user limits for abuse or capacity, so “B is unaffected” applies only to the selected account rule. The NIST verifier requirements call for failed-attempt controls; thresholds here are synthetic test settings.

Source