pyjwt
pyjwt copied to clipboard
Support swapping out the cache backend for JWKClient
Great project!
I'm using it with my Django project, where it runs multiple containers with scaling. I have a redis server shared between these instances.
I would like to cache JWKs in redis. I could provide a PR if people are interested.
I'd propose the following:
from typing import Protocol
from .jwk_set_cache import JWKSetCache
class JWKSetCacheProtocol(Protocol):
def put(self, jwk_set: PyJWKSet) -> None: ...
...
def get(self) -> Optional[PyJWKSet]:
...
def is_expired(self) -> bool:
...
class PyJWKClient:
def __init__(
self,
uri: str,
cache_keys: bool = False,
max_cached_keys: int = 16,
cache_jwk_set: bool = True,
lifespan: int = 300,
headers: Optional[Dict[str, Any]] = None,
timeout: int = 30,
ssl_context: Optional[SSLContext] = None,
jwk_set_cache: Optional[JWKSetCacheProtocol] = None,
):
if headers is None:
headers = {}
self.uri = uri
self.jwk_set_cache: Optional[JWKSetCache] = None
self.headers = headers
self.timeout = timeout
self.ssl_context = ssl_context
if jwk_set_cache:
self.jwk_set_cache = jwk_set_cache
elif cache_jwk_set:
# Init jwt set cache with default or given lifespan.
# Default lifespan is 300 seconds (5 minutes).
if lifespan <= 0:
raise PyJWKClientError(
f'Lifespan must be greater than 0, the input is "{lifespan}"'
)
self.jwk_set_cache = JWKSetCache(lifespan)
else:
self.jwk_set_cache = None
if cache_keys:
# Cache signing keys
# Ignore mypy (https://github.com/python/mypy/issues/2427)
self.get_signing_key = lru_cache(maxsize=max_cached_keys)(self.get_signing_key) # type: ignore
This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days
This is a good approach for APIs that throttle requests and could end up returning 429's to JWK fetches, when multiple workers run concurrently.
At the moment, the hacky workaround is to override the jwk_set_cache client attribute right after instantiating it, replacing it with a Redis client that implements the Protocol you suggested.
This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days
This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days