Skip to content

feat(security): add per-IP rate limiting with Redis + in-memory support#568

Merged
lakhansamani merged 11 commits intomainfrom
fix/h9-rate-limiting-v2
Apr 4, 2026
Merged

feat(security): add per-IP rate limiting with Redis + in-memory support#568
lakhansamani merged 11 commits intomainfrom
fix/h9-rate-limiting-v2

Conversation

@lakhansamani
Copy link
Copy Markdown
Contributor

Summary

  • Adds per-IP rate limiting middleware to all auth endpoints
  • Supports multi-replica deployments via Redis sliding-window (Lua script), with in-memory (golang.org/x/time/rate) fallback for single-instance
  • Configurable via CLI: --rate-limit-rps (default: 10) and --rate-limit-burst (default: 20)
  • Always enabled; set --rate-limit-rps=0 to disable
  • Fail-open on errors (auth availability > rate limiting)
  • Returns 429 Too Many Requests with Retry-After: 1 header and OAuth2 error format

Changes

  • internal/rate_limit/ — New package with Provider interface, inMemoryProvider (token bucket via x/time/rate + sync.Map), and redisProvider (atomic Lua sliding-window script)
  • internal/config/config.go — Added RateLimitRPS and RateLimitBurst fields
  • cmd/root.go — Added --rate-limit-rps and --rate-limit-burst CLI flags, wired provider (reuses Redis connection from memory store when available)
  • internal/http_handlers/rate_limit.go — Rewrote middleware: calls provider, skips 10 exempt paths (health, metrics, OIDC discovery, static assets)
  • internal/http_handlers/provider.go — Added RateLimitProvider to Dependencies
  • internal/server/http_routes.go — Placed middleware after CORS, before ClientCheck
  • internal/memory_store/redis/provider.go — Added Eval to RedisClient interface, exposed Client() method
  • CLAUDE.md — Added critical rule: never commit to main

Exempt paths (not rate limited)

/, /health, /healthz, /readyz, /metrics, /playground, /.well-known/openid-configuration, /.well-known/jwks.json, /app/*, /dashboard/*

Security considerations

  • Per-IP isolation prevents one attacker from exhausting limits for others
  • Redis Lua script executes atomically — no TOCTOU races across replicas
  • Fail-open ensures auth availability when Redis is temporarily down
  • Retry-After header per RFC 6585 for well-behaved clients
  • Protects brute-force targets: /graphql, /oauth/token, /oauth_login, /verify_email, etc.

Test plan

  • TestRateLimitMiddleware/should_allow_requests_within_limit
  • TestRateLimitMiddleware/should_reject_requests_over_limit (burst exhaustion → 429)
  • TestRateLimitMiddleware/should_not_rate_limit_exempt_paths (health, metrics, OIDC)
  • TestRateLimitMiddleware/should_isolate_rate_limits_per_ip
  • TestRateLimitMiddleware/should_return_correct_error_format (OAuth2 error + Retry-After)
  • TestInMemoryRateLimitProvider/should_allow_up_to_burst
  • TestInMemoryRateLimitProvider/should_deny_after_burst
  • All 7 tests pass with TEST_DBS=sqlite
  • Full build: go build ./... passes

Covers multi-replica aware rate limiting with Redis sliding window
(distributed) and x/time/rate in-memory fallback, CLI configurability
via --rate-limit-rps and --rate-limit-burst, and exempt path list.
7-task plan covering config/CLI flags, rate_limit provider package
(in-memory + Redis), middleware rewrite, wiring, and integration tests.
Introduces the rate_limit package with a Provider interface and an
in-memory token-bucket implementation backed by golang.org/x/time/rate.
Includes a Redis stub that will be replaced in Task 3.
- Remove applyFlagDefaults override so --rate-limit-rps=0 disables rate limiting
- Add defer rateLimitProvider.Close() for graceful shutdown
- Simplify Redis Lua script: remove redundant GET, use INCR-only pattern
- Add compile-time interface guards for inMemoryProvider and redisProvider
- Document benign lastSeen data race in entry struct
Add critical rule #6 to CLAUDE.md: always use feature branches,
push to branch, create merge request. Main must stay deployable.
@lakhansamani lakhansamani merged commit 2fa08cb into main Apr 4, 2026
@lakhansamani lakhansamani deleted the fix/h9-rate-limiting-v2 branch April 4, 2026 12:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant