Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support swapping out the cache backend for JWKClient #981

Open
rabbit-aaron opened this issue Aug 29, 2024 · 2 comments
Open

Support swapping out the cache backend for JWKClient #981

rabbit-aaron opened this issue Aug 29, 2024 · 2 comments

Comments

@rabbit-aaron
Copy link

rabbit-aaron commented Aug 29, 2024

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
Copy link

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

@github-actions github-actions bot added the stale Issues without activity for more than 60 days label Oct 29, 2024
@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Nov 6, 2024
@adamantike
Copy link

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.

@auvipy auvipy reopened this Feb 5, 2025
@auvipy auvipy removed the stale Issues without activity for more than 60 days label Feb 5, 2025
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

No branches or pull requests

3 participants