Enforce JWT Authentication With RS256 and Key Rotation
This snippet configures FastAPI's HTTPBearer security scheme with PyJWT verifying RS256 signatures against a JWKS endpoint that is cached and refreshed on key ID mismatch. The dependency decodes the token, validates exp, nbf, iss, and aud, and injects a typed user principal into the route. Internally, PyJWT selects the public key by the kid header, and the cache short-circuits network calls on the hot path.
Production use cases include multi-tenant SaaS where tokens are issued by an external IdP such as Auth0, Keycloak, or AWS Cognito. RS256 is preferred over HS256 because the API only holds the public key, so a compromised API server cannot mint tokens. Key rotation is handled transparently when the IdP publishes a new kid, provided the cache TTL is short enough (typically 300 seconds) and the refresh is triggered on unknown kid.
Security pitfalls: never disable audience or issuer validation, as this enables token confusion attacks across tenants. Do not use HS256 with a shared secret exposed to every service. Always enforce a clock skew leeway of at most 30 seconds and reject alg=none explicitly. Performance impact is minimal because RSA verification is sub-millisecond, but fetching JWKS on every request is a real DoS vector; the cached approach with a single-flight lock prevents thundering herd on rotation.
> System.Execute()
pip install "pyjwt[crypto]" cryptography httpx cachetools
# app/security.py
from typing import Annotated
import jwt, httpx
from cachetools import TTLCache
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
JWKS_URL = "https://idp.internal/.well-known/jwks.json"
ISSUER = "https://idp.internal/"
AUDIENCE = "fastapi-api"
_jwks = TTLCache(maxsize=4, ttl=300)
bearer = HTTPBearer(auto_error=True)
def _keys():
if "data" not in _jwks:
_jwks["data"] = httpx.get(JWKS_URL, timeout=2.0).json()
return _jwks["data"]["keys"]
def principal(creds: Annotated[HTTPAuthorizationCredentials, Depends(bearer)]):
try:
header = jwt.get_unverified_header(creds.credentials)
key = next(k for k in _keys() if k["kid"] == header["kid"])
return jwt.decode(creds.credentials, jwt.algorithms.RSAAlgorithm.from_jwk(key),
algorithms=["RS256"], issuer=ISSUER, audience=AUDIENCE,
leeway=30, options={"require": ["exp", "iat", "sub"]})
except Exception as e:
raise HTTPException(status.HTTP_401_UNAUTHORIZED, "invalid token") from e
> Architecture & Security Context
Verified for Valters IT Hub. When deploying this configuration in a production homelab or enterprise environment, ensure that you monitor system resources and implement strict access controls. Administrator privileges are required.
ID: VALTERSIT-4CE12EC66E6F