Rate limit by the key or user, and by IP only as the fallback
Limiting by IP throttles an office of a thousand people behind one NAT and does nothing about one attacker with a thousand addresses. Limit the thing that identifies the caller.
const key = apiKey ?? userId ?? ip;
await limiter.consume(key);Return 429 with a Retry-After header so well-behaved clients back off instead of hammering.
securityhttp