Free — no signup required

Caching Strategies: Don't DoS Your Own Auth Server

2 min read

The Performance Trap

The JWKS endpoint is a public HTTP URL. If your verification middleware fetches it on every incoming API request, you introduce two catastrophic failure modes:

  1. Latency: Every request now has a synchronous network round-trip to the auth server before it can be processed. At 10ms per fetch and 1,000 RPS, that's 10 seconds of cumulative auth-server load per second of traffic.
  2. Self-inflicted DDoS: Your own services become the attacker. The auth server gets hammered and falls over, taking authentication down for your entire platform.

The Smart Caching Pattern

Production JWT libraries implement a fetch-cache-refresh pattern:

1. First request arrives with kid: "key-id-123"
   → Cache is empty → Fetch JWKS → Store all keys in memory → Verify token

2. Next 10,000 requests arrive with kid: "key-id-123"
   → Cache hit → Verify token (no network call)

3. Request arrives with kid: "key-id-456" (rotation happened)
   → Cache miss for this kid → Fetch fresh JWKS → Update cache → Verify token

4. Attacker sends 1,000 requests with random kid: "garbage-xyz"
   → Cache miss → Rate limit: only fetch JWKS once per 60 seconds
   → Reject token (key not found) without hammering auth server

Rate-Limiting Cache Refreshes

Step 4 above is critical. Without a rate limit on cache refreshes, an attacker can craft tokens with random kid values to force your service to make thousands of requests to the auth server per second — a cache-busting DDoS attack.

The defense: track the last time you fetched the JWKS. If a kid is not found in cache, only trigger a refresh if the last refresh was more than N seconds ago (typically 60 seconds). If the key still isn't found after a fresh fetch, reject the token.

Library Support

Most mature JWT libraries handle this automatically:

Library Language JWKS Caching
jose Node.js Built-in with createRemoteJWKSet()
python-jose Python Manual caching required
nimbus-jose-jwt Java Built-in RemoteJWKSet with caching
golang-jwt + jwks-go Go Via keyfunc package

Key Point: Never implement raw JWKS fetching without caching. Always use a library that implements refresh-on-miss with rate limiting, or implement those controls explicitly yourself.

This is one of 18 chapters

Every chapter is free — Kubernetes, Terraform, SRE, distributed systems, and more — with fast daily review built in.

Sign up free