Rate Limiting Configuration

Protect your IdentitySuite instance from abuse and excessive API usage with comprehensive rate limiting policies and monitoring

Rate Limiting Configuration

Rate limiting protects IdentitySuite from abuse and excessive API usage by controlling the number of requests clients can make within specific time windows. All rate limiting policies use SlidingWindowRateLimiterOptions to provide flexible and granular control over request throttling.

Requests are classified by OpenIddict's endpoint type, not by URL path - so the correct policy still applies even if an endpoint has been remapped to a non-default path.

Rejected Request Behavior:

Every policy above returns HTTP 429 Too Many Requests when a client exceeds its limit - including the Configuration, JsonWebKeySet and PushedAuthorization endpoints, where OpenIddict's default OAuth error mapping would otherwise surface a plain 400. Identity Endpoints (Account pages) return the same 429 even though they never go through the OAuth error pipeline at all.

Retry-After header: only sent when actually available. The SlidingWindowRateLimiterOptions used by every policy above does not currently report a retry time on a rejected request - a known limitation of the underlying .NET rate limiter itself, not something withheld by IdentitySuite. Clients that build automatic retry/backoff on top of these endpoints should not assume this header will be present and should fall back to their own backoff strategy.

Rate Limiting Controls:

Rate limiting enabled: Master switch to enable/disable all rate limiting policies
Rate limiting metrics enabled: Enables collection and display of rate limiting statistics and analytics
Default: enabled out of the box in Production and Staging (disabled in Development, to avoid getting in the way of local testing). This applies to new projects only - identitySuiteSettings.*.json is copied into your project once when the package is first added and is never overwritten by later package updates, so an existing installation keeps whatever value it already has until you change it yourself here or directly in the JSON file.

OIDC Critical Endpoints (High-Risk):

High-risk OIDC endpoints vulnerable to abuse through automated attacks and resource exhaustion. These endpoints handle authentication flows and token generation, making them prime targets for brute force and DoS attacks. Partitioned by client IP. Endpoint types: Authorization, PushedAuthorization, UserInfo, DeviceAuthorization, and Token requests without a client_id.

SlidingWindowRateLimiterOptions Parameters:

PermitLimit: Maximum requests allowed (Default: 20)
Window: Time window duration (Default: 5 minutes)
SegmentsPerWindow: Window subdivisions for smoother limiting (Default: 10)
QueueLimit: Queued requests when limit exceeded (Default: 0)
AutoReplenishmentEnable: Automatically replenishes permits as time progresses within the sliding window

OIDC Default Endpoints (Moderate-Risk):

Standard OIDC endpoints with moderate risk exposure. These endpoints handle session termination and token introspection, requiring protection against automated scraping and session abuse attacks. Partitioned by client IP. Endpoint types: EndSession, EndUserVerification, Revocation, and Introspection requests without a client_id.

SlidingWindowRateLimiterOptions Parameters:

PermitLimit: Maximum requests allowed (Default: 60)
Window: Time window duration (Default: 5 minutes)
SegmentsPerWindow: Window subdivisions for smoother limiting (Default: 10)
QueueLimit: Queued requests when limit exceeded (Default: 0)
AutoReplenishmentEnable: Automatically replenishes permits as time progresses within the sliding window

OIDC Client Endpoints (Partitioned by Client):

Token and Introspection requests that carry a client_id are partitioned by client instead of by IP. This protects a legitimate high-volume client (e.g. a backend service issuing client-credentials or refresh-token requests) from being penalized just because other clients share the same IP address, while still limiting each client individually. Endpoint types: Token, Introspection (only when a client_id is present).

SlidingWindowRateLimiterOptions Parameters:

PermitLimit: Maximum requests allowed (Default: 300)
Window: Time window duration (Default: 1 minute)
SegmentsPerWindow: Window subdivisions for smoother limiting (Default: 6)
QueueLimit: Queued requests when limit exceeded (Default: 0)
AutoReplenishmentEnable: Automatically replenishes permits as time progresses within the sliding window

Global Endpoints (Baseline Protection):

Fallback policy for OIDC endpoint types not covered by a more specific policy - in practice mainly Configuration (discovery) and JsonWebKeySet (JWKS), which expose only public, cacheable metadata, so this permissive baseline is a deliberate choice rather than a gap. Scope: only within the OIDC pipeline. Plain application pages are out of reach for this policy by construction - OpenIddict's ProcessRequestContext fires for every request that reaches its ASP.NET Core middleware, but it can only build a rejection response for endpoint types it recognizes; calling Reject() for an unrecognized (Unknown) endpoint throws instead of returning a response. The handler therefore skips enforcement entirely for Unknown endpoint types - see Identity Endpoints below for rate limiting plain application pages instead.

SlidingWindowRateLimiterOptions Parameters:

PermitLimit: Maximum requests allowed (Default: 100)
Window: Time window duration (Default: 5 minutes)
SegmentsPerWindow: Window subdivisions for smoother limiting (Default: 5)
QueueLimit: Queued requests when limit exceeded (Default: 0)
AutoReplenishmentEnable: Automatically replenishes permits as time progresses within the sliding window

Identity Endpoints (Account Pages, Partitioned by IP):

Unlike every other policy above, this one is enforced by a plain ASP.NET Core middleware, not an OpenIddict handler - it protects POST requests to the Account pages (login, register, 2FA, forgot/reset password, and the self-service pages under Account/Manage such as change password/email), which never go through the OIDC pipeline. ASP.NET Identity's own account lockout already protects a single account from brute force; it does not stop password spraying (many accounts, few passwords, no single account ever reaches its lockout threshold), user enumeration via register/forgot-password, or registration/email flooding - this policy fills that gap by limiting per source IP. Only POST requests under /Account/ are limited; GET requests (page rendering) never are, and the admin panel under /Manage/ is a separate, already-authenticated area out of scope for this policy.

SlidingWindowRateLimiterOptions Parameters:

PermitLimit: Maximum requests allowed (Default: 10)
Window: Time window duration (Default: 5 minutes)
SegmentsPerWindow: Window subdivisions for smoother limiting (Default: 10)
QueueLimit: Queued requests when limit exceeded (Default: 0)
AutoReplenishmentEnable: Automatically replenishes permits as time progresses within the sliding window. A deliberately conservative default (10 requests/5 minutes) - low enough to catch automated spraying, high enough that a user who mistypes their password a few times stays under it. Offices behind NAT/shared IPs should use the whitelist rather than raising this below 10.

IP Address Management:

White Listed IPs:
  • • IP addresses exempt from all rate limiting
  • • Trusted sources and administrative access
  • • Add IP addresses that should never be throttled
Black Listed IPs:
  • • IP addresses completely blocked from access
  • • Known malicious sources and threat actors
  • • Automatically reject all requests from these IPs
Client IP resolution: only the direct TCP connection's remote address is trusted by default - X-Forwarded-For/X-Forwarded-Proto headers are client-controlled and ignored unless a reverse proxy is explicitly configured, see Reverse Proxy Configuration below. Without that configuration, an application running behind a real reverse proxy will rate-limit and whitelist/blacklist by the proxy's own IP, not the client's.
Input validation: only complete, correctly formatted IP addresses and CIDR networks are accepted when adding an entry - shortened dotted-quad forms (e.g. 1.1.1, 10/8) that some parsers accept as a legacy shorthand are rejected, closing a known IP-filter bypass vector.

Reverse Proxy Configuration:

Disabled by default. Without an explicitly trusted proxy, the direct TCP connection's remote address is the only source of the client IP that cannot be spoofed by the client - enabling this without a real reverse proxy in front of the application would let any client forge its own X-Forwarded-For header and bypass rate limiting, whitelisting, and blacklisting entirely.

Enabled: master switch for trusting X-Forwarded-For/X-Forwarded-Proto headers
Known Proxies: individual IP addresses of trusted reverse proxies (e.g. 10.0.0.5)
Known Networks: CIDR ranges of trusted reverse proxy networks (e.g. 10.0.0.0/24)
Format: only fully-qualified addresses/networks are accepted, same validation as the white/black lists above
Only enable this when the application actually sits behind a reverse proxy (e.g. IIS, Nginx, a load balancer, or a container ingress) and list every hop between the proxy and the application - forwarded headers are trusted only when they originate from a connection whose remote address matches an entry in Known Proxies or Known Networks. Application restart required for changes to take effect.

Understanding SlidingWindowRateLimiterOptions:

Sliding Window Algorithm: Unlike fixed windows that reset at specific intervals, sliding windows continuously track requests over a moving time period, providing smoother rate limiting without sudden bursts.
PermitLimit: The maximum number of requests allowed within the window period.
Window: The duration of the sliding time window (e.g., 5 minutes, 1 hour).
SegmentsPerWindow: Divides the window into smaller segments for more precise tracking. Higher values provide smoother limiting but use more memory.
QueueLimit: Number of requests to queue when the limit is exceeded. Set to 0 to immediately reject excess requests.
AutoReplenishmentEnable: Automatically makes new permits available as time progresses, rather than waiting for the full window to slide.

Rate Limiting Metrics and Monitoring:

Important: All metrics are stored in memory and are not persistent. Data is lost when the server process restarts, including IIS app pool recycling, application restarts, or server reboots. Metrics are designed for real-time policy evaluation and monitoring.
Memory bounds (RateLimiting:Metrics): raw per-request detail is capped by MaxEntries (default 100,000 - oldest entries are dropped once exceeded) and kept for RawRetention (default 1 day). The dashboard's 7-day view still shows accurate policy totals beyond that window via long-term hourly aggregates, but per-client and per-endpoint breakdowns are only available for the raw retention window. Without these bounds, the metrics store itself becomes a memory-exhaustion vector under sustained traffic - Configuration/JsonWebKeySet requests are also only recorded when actually denied, since an allowed request there is routine, high-volume noise.
Real-time Metrics:
  • Rejection Rate: Percentage of requests being blocked
  • Unique Clients: Number of distinct IP addresses
  • Active Policies: Currently enforced rate limit policies
  • Suspicious Clients: IPs showing potential abuse patterns
Analytics Views:
  • Statistics Policy: Per-policy performance data
  • Popular Endpoints: Most frequently accessed endpoints
  • Client Requests: Top requesting IP addresses
  • Time Trends: Request patterns over time
Time Views: Last hour, Last day, Last week

Configuration Guidelines:

  • • Test rate limiting policies in a development environment first
  • • Monitor metrics regularly to adjust limits based on actual usage patterns
  • • Consider legitimate high-traffic scenarios when setting limits
  • • White-list trusted IP addresses to prevent accidental blocking
  • • Application restart required for configuration changes to take effect