Skip to main content
Version: 2.x (Latest)

Rate Limiting

Authorizer includes built-in per-IP rate limiting to protect authentication endpoints from brute-force attacks and abuse. Rate limiting is always enabled by default with sensible defaults, and supports multi-replica deployments via Redis.

How it works

Every incoming request is tracked by client IP address. Each IP is allowed a sustained request rate (--rate-limit-rps) with a burst allowance (--rate-limit-burst). When an IP exceeds the limit, Authorizer responds with 429 Too Many Requests and a Retry-After header.

Single instance: Rate limits are tracked in memory using a token bucket algorithm. No external dependencies required.

Multi-replica: When Redis is configured (--redis-url), rate limits are shared across all replicas using an atomic Redis sliding-window counter (Lua script). This ensures consistent enforcement regardless of which replica handles the request.

Fail-open behavior: If Redis becomes temporarily unavailable, the rate limiter allows requests through rather than blocking legitimate users. Auth availability takes priority over rate limiting.


CLI Flags

FlagDefaultDescription
--rate-limit-rps10Maximum sustained requests per second per IP
--rate-limit-burst20Maximum burst size per IP (allows short spikes above the sustained rate)
./build/server \
--rate-limit-rps=10 \
--rate-limit-burst=20

Customizing limits

For high-traffic deployments, increase the limits:

./build/server \
--rate-limit-rps=50 \
--rate-limit-burst=100

For stricter protection (e.g., a small internal deployment):

./build/server \
--rate-limit-rps=5 \
--rate-limit-burst=10

Disabling rate limiting

If your infrastructure already provides rate limiting (e.g., API gateway, CDN, or load balancer), you can disable it:

./build/server \
--rate-limit-rps=0

Exempt endpoints

The following endpoints are not rate limited because they are infrastructure, static assets, or standards-required discovery endpoints:

PathReason
/Root/info endpoint
/healthKubernetes liveness probe
/healthzKubernetes liveness probe
/readyzKubernetes readiness probe
/metricsPrometheus scrape endpoint
/playgroundGraphQL playground (dev tool)
/.well-known/openid-configurationOIDC discovery (cacheable, spec-required)
/.well-known/jwks.jsonJWKS endpoint (cacheable, spec-required)
/app/*Static frontend assets (login UI)
/dashboard/*Static frontend assets (admin UI)

All other endpoints are rate limited, including:

  • /graphql (all auth mutations: signup, login, reset password, etc.)
  • /oauth/token (token exchange)
  • /oauth/revoke (token revocation)
  • /oauth_login/:provider and /oauth_callback/:provider (OAuth flows)
  • /authorize (OAuth2 authorize)
  • /userinfo (token-based user info)
  • /verify_email (email verification)
  • /logout (session termination)

Rate limit response

When a client exceeds the rate limit, Authorizer returns:

HTTP/1.1 429 Too Many Requests
Retry-After: 1
Content-Type: application/json

{
"error": "rate_limit_exceeded",
"error_description": "Too many requests. Please try again later."
}

The Retry-After: 1 header tells clients to wait at least 1 second before retrying (per RFC 6585).


Multi-replica setup with Redis

For deployments with multiple Authorizer replicas, configure Redis to ensure rate limits are shared:

./build/server \
--redis-url=redis://user:pass@redis-host:6379/0 \
--rate-limit-rps=10 \
--rate-limit-burst=20

When --redis-url is set, Authorizer automatically uses Redis for both session storage and rate limiting. No additional configuration is needed.

Redis Cluster

Redis Cluster is also supported. Provide multiple URLs:

./build/server \
--redis-url="redis://node1:6379,node2:6380,node3:6381"

Docker Compose example

services:
authorizer:
image: lakhansamani/authorizer:latest
command:
- --database-type=postgres
- --database-url=postgres://user:pass@db:5432/authorizer
- --redis-url=redis://redis:6379
- --rate-limit-rps=10
- --rate-limit-burst=20
- --client-id=YOUR_CLIENT_ID
- --client-secret=YOUR_CLIENT_SECRET
ports:
- "8080:8080"
depends_on:
- db
- redis
deploy:
replicas: 3

redis:
image: redis:7-alpine
ports:
- "6379:6379"

db:
image: postgres:15
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: authorizer

Monitoring rate limits

Rate limit rejections appear in Authorizer's HTTP metrics:

# Rate of 429 responses (rate-limited requests)
rate(authorizer_http_requests_total{status="429"}[5m])

# Rate-limited requests by path
sum(rate(authorizer_http_requests_total{status="429"}[5m])) by (path)

Alerting example

groups:
- name: authorizer-rate-limit
rules:
- alert: HighRateLimitRate
expr: rate(authorizer_http_requests_total{status="429"}[5m]) > 1
for: 5m
labels:
severity: warning
annotations:
summary: "High rate of rate-limited requests"
description: "More than 1 req/sec being rate-limited for 5 minutes. Possible attack or misconfigured client."

See Metrics & Monitoring for the full metrics reference.