ctx.request.user?.id — the authenticated principal, when auth middleware ran first.
ctx.state.get(CLIENT_IP_STATE_KEY) — the client IP ipSecurityMiddleware publishes.
With proxy trust off it publishes the socket peer. See the warning below:
trustProxy alone can make this key attacker-controlled.
ctx.request.ip — the socket peer on Node, Deno and Bun (M113n), normalized
from IPv4-mapped IPv6. Workers and plain fetch calls have no peer.
'anonymous'.
A forwarded entry that is not an address resolves no client, so the key falls back to the socket peer, or 'anonymous' without one.
The 'anonymous' fallback makes the limiter one GLOBAL counter — max
requests per window across ALL callers, which both starves legitimate traffic
and fails to limit any individual client. Socket-serving adapters now count
per peer even without IP security. Behind a proxy, register IP security to
resolve clients rather than proxies; on Workers supply a trusted header or
your own keyGenerator. Put the limiter after authentication to count users.
trustProxy: true alone is not enough, and this is the sharper hazard of
the two. It resolves the LEFTMOST entry of the proxy header, which is safe
only behind a proxy that OVERWRITES that header. The standard nginx idiom
(proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for) APPENDS, so a
request arriving with a forged X-Forwarded-For: 7.7.7.7 reaches the
application as 7.7.7.7, 198.51.100.9 and this function keys the limiter on
the value the caller chose — rotating it defeats the budget entirely, which is
worse than the global counter above because it looks configured. Behind an
appending proxy, set ipSecurityMiddleware({ trustProxy: true, trustedProxies })
(or proxyHops) so the client is resolved from the right.
Default rate-limit key, in order of preference:
ctx.request.user?.id— the authenticated principal, when auth middleware ran first.ctx.state.get(CLIENT_IP_STATE_KEY)— the client IPipSecurityMiddlewarepublishes. With proxy trust off it publishes the socket peer. See the warning below:trustProxyalone can make this key attacker-controlled.ctx.request.ip— the socket peer on Node, Deno and Bun (M113n), normalized from IPv4-mapped IPv6. Workers and plain fetch calls have no peer.'anonymous'. A forwarded entry that is not an address resolves no client, so the key falls back to the socket peer, or'anonymous'without one.The
'anonymous'fallback makes the limiter one GLOBAL counter —maxrequests per window across ALL callers, which both starves legitimate traffic and fails to limit any individual client. Socket-serving adapters now count per peer even without IP security. Behind a proxy, register IP security to resolve clients rather than proxies; on Workers supply a trusted header or your ownkeyGenerator. Put the limiter after authentication to count users.trustProxy: truealone is not enough, and this is the sharper hazard of the two. It resolves the LEFTMOST entry of the proxy header, which is safe only behind a proxy that OVERWRITES that header. The standard nginx idiom (proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for) APPENDS, so a request arriving with a forgedX-Forwarded-For: 7.7.7.7reaches the application as7.7.7.7, 198.51.100.9and this function keys the limiter on the value the caller chose — rotating it defeats the budget entirely, which is worse than the global counter above because it looks configured. Behind an appending proxy, setipSecurityMiddleware({ trustProxy: true, trustedProxies })(orproxyHops) so the client is resolved from the right.