Middleware factory for the product's security throttles (#325).
One implementation of the rate-limit check + outage policy shared by the
OAuth endpoints (/token, /authorize, /introspect) and
/session/login, which previously carried two hand-synchronized copies
(#314) that had already drifted: only the oauth copy emitted the
rate_limit.unavailable audit event, and only the session copy emitted
RateLimit-* headers. Both surfaces now do both.
The guard checks limiter.check("<tag>:ip:<ip>", ctx) and:
allow → emits RateLimit-* headers and calls next();
deny → emits RateLimit-* headers, Retry-After when the decision
carries a reset time, and a 429 with the RFC 6749 §5.2 envelope
({error: "rate_limited"} — AS-2 unified error shape);
limiter outage → applies failMode (OR-5). The previous
implementation was silent fail-open with a fire-and-forget audit event.
The audit sink is typically Redis-backed too, so during a Redis outage
the audit emission also silently drops — operators saw nothing while
rate limiting was down for hours. The failMode policy makes the
behavior configurable, and the logger.error call ensures operators see
the outage regardless of audit-sink status. Belt-and-suspenders: the
rate_limit.unavailable audit event is kept for ops dashboards that
consume it — the logger call is the operator-visible path, the audit
event is the structured pipeline path.
Middleware factory for the product's security throttles (#325).
One implementation of the rate-limit check + outage policy shared by the OAuth endpoints (
/token,/authorize,/introspect) and/session/login, which previously carried two hand-synchronized copies (#314) that had already drifted: only the oauth copy emitted therate_limit.unavailableaudit event, and only the session copy emittedRateLimit-*headers. Both surfaces now do both.The guard checks
limiter.check("<tag>:ip:<ip>", ctx)and:RateLimit-*headers and callsnext();RateLimit-*headers,Retry-Afterwhen the decision carries a reset time, and a 429 with the RFC 6749 §5.2 envelope ({error: "rate_limited"}— AS-2 unified error shape);failMode(OR-5). The previous implementation was silent fail-open with a fire-and-forget audit event. The audit sink is typically Redis-backed too, so during a Redis outage the audit emission also silently drops — operators saw nothing while rate limiting was down for hours. ThefailModepolicy makes the behavior configurable, and thelogger.errorcall ensures operators see the outage regardless of audit-sink status. Belt-and-suspenders: therate_limit.unavailableaudit event is kept for ops dashboards that consume it — the logger call is the operator-visible path, the audit event is the structured pipeline path.