{"id":7576,"library":"pyjwt-key-fetcher","title":"PyJWT Key Fetcher","description":"PyJWT Key Fetcher is an async Python library designed to fetch JSON Web Key Sets (JWKS) for JWT token verification. It automatically retrieves issuer configurations (e.g., from OpenID Connect discovery endpoints) to locate JWKS URIs and fetch the correct public keys. This library acts as an improved async replacement for `PyJWKClient` from PyJWT. The current version is 0.8.0, and it maintains a relatively active release cadence with several updates per year.","status":"active","version":"0.8.0","language":"en","source_language":"en","source_url":"https://github.com/ioxiocom/pyjwt-key-fetcher","tags":["jwt","jwks","openid connect","async","security","key management","pyjwt"],"install":[{"cmd":"pip install pyjwt-key-fetcher","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Core JWT encoding/decoding, this library provides key fetching for it.","package":"PyJWT","optional":false},{"reason":"Used internally for asynchronous HTTP requests to fetch configurations and JWKS.","package":"aiohttp","optional":false},{"reason":"Required by PyJWT for RSA/ECDSA algorithms commonly used with JWKS.","package":"cryptography","optional":true}],"imports":[{"symbol":"AsyncKeyFetcher","correct":"from pyjwt_key_fetcher import AsyncKeyFetcher"},{"note":"Class was renamed from OpenIDProvider to Provider in v0.3.0 for generic JWT provider support.","wrong":"from pyjwt_key_fetcher.openid_provider import OpenIDProvider","symbol":"Provider","correct":"from pyjwt_key_fetcher.provider import Provider"}],"quickstart":{"code":"import asyncio\nimport jwt\nfrom pyjwt_key_fetcher import AsyncKeyFetcher\n\nasync def main():\n    # Example token from PyJWT documentation for demonstration\n    # In a real app, this would come from an Authorization header\n    token = \"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik5FRTFRVVJCT1RNNE16STVSa0ZETlRZeE9UVTFNRGcyT0Rnd1EwVXpNVGsxUWpZeVJrUkZRdyJ9.eyJpc3MiOiJodHRwczovL2Rldi04N2V2eDlydS5hdXRoMC5jb20vIiwic3ViIjoiYVc0Q2NhNzl4UmVMV1V6MGFFMkg2a0QwTzNjWEJWdENAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vZXhwZW5zZXMtYXBpIiwiaWF0IjoxNTcyMDA2OTU0LCJleHAiOjE1NzIwMDY5NjQsImF6cCI6ImFXNENjYTc5eFJlTFdVejBhRTJINmtEME8zY1hCVnRDIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.PUxE7xn52aTCohGiWoSdMBZGiYAHwE5FYie0Y1qUT68IHSTXwXVd6hn02HTah6epvHHVKA2FqcFZ4GGv5VTHEvYpeggiiZMgbxFrmTEY0csL6VNkX1eaJGcuehwQCRBKRLL3zKmA5IKGy5GeUnIbpPHLHDxr-GXvgFzsdsyWlVQvPX2xjeaQ217r2PtxDeqjlf66UYl6oY6AqNS8DH3iryCvIfCcybRZkc_hdy-6ZMoKT6Piijvk_aXdm7-QQqKJFHLuEqrVSOuBqqiNfVrG27QzAPuPOxvfXTVLXL2jek5meH6n-VWgrBdoMFH93QEszEDowDAEhQPHVs0xj7SIzA\"\n\n    fetcher = AsyncKeyFetcher(valid_issuers=[\"https://dev-87evx9ru.auth0.com/\"])\n    try:\n        key_entry = await fetcher.get_key(token)\n        # The fetched key_entry can then be used with PyJWT's decode function\n        decoded_token = jwt.decode(\n            jwt=token,\n            options={\"verify_exp\": False}, # Set to True for production\n            audience=\"https://expenses-api\",\n            issuer=\"https://dev-87evx9ru.auth0.com/\",\n            **key_entry\n        )\n        print(\"Successfully decoded token:\", decoded_token)\n    except Exception as e:\n        print(f\"Error decoding token: {e}\")\n\nif __name__ == \"__main__\":\n    asyncio.run(main())","lang":"python","description":"This example demonstrates how to use `AsyncKeyFetcher` to retrieve a signing key from a JWT's issuer, and then use that key with `PyJWT` to decode and verify the token. It includes `valid_issuers` for security and explicitly passes `audience` and `issuer` to `jwt.decode` for full validation."},"warnings":[{"fix":"Update method/class names (e.g., `fetcher.get_configuration()` instead of `fetcher.get_openid_configuration()`, `Provider` instead of `OpenIDProvider`). Refer to the v0.3.0 changelog for all renamed symbols.","message":"Major refactoring in v0.3.0 renamed all explicit OpenID Connect references to be more generic. This includes `get_openid_configuration` to `get_configuration`, `OpenIDProvider` to `Provider`, and `JWTOpenIDConnectError` exceptions.","severity":"breaking","affected_versions":"<0.3.0"},{"fix":"Replace `OpenIDConfigurationTypeDef` with `ConfigurationTypeDef` in type hints or direct references.","message":"The type definition `OpenIDConfigurationTypeDef` was removed in v0.8.0. You should now use `ConfigurationTypeDef` instead.","severity":"breaking","affected_versions":"<0.8.0"},{"fix":"Adjust caching parameters (`cache_maxsize`, `cache_ttl`) during `AsyncKeyFetcher` initialization to match your security requirements and acceptable latency for key revocation propagation. E.g., `AsyncKeyFetcher(cache_ttl=600)` for 10-minute cache.","message":"The `AsyncKeyFetcher` uses caching with a default TTL (Time To Live) of 3600 seconds (1 hour) for JWKS data. This means key revocations might not take effect immediately, as the old key could remain in the cache. New `kid` values will trigger a re-fetch if not seen in 5 minutes.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Always pass `audience` and `issuer` to `jwt.decode()` after fetching the key, ensuring they match the expected values for your application. E.g., `jwt.decode(..., audience=my_app_aud, issuer=expected_issuer, **key_entry)`.","message":"While `pyjwt-key-fetcher` retrieves the correct signing key, `jwt.decode()` from PyJWT still requires explicit `audience` and `issuer` parameters for full validation, especially when dealing with OIDC tokens. Failing to provide these can lead to tokens being accepted that shouldn't be.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"The method `get_openid_configuration` was renamed to `get_configuration` in v0.3.0. Use `await fetcher.get_configuration(token)` instead.","cause":"Attempting to call a method that was renamed in version 0.3.0.","error":"AttributeError: 'AsyncKeyFetcher' object has no attribute 'get_openid_configuration'"},{"fix":"Ensure all calls to `AsyncKeyFetcher` methods (like `get_key`, `get_configuration`) are prefixed with `await`. Also, `AsyncKeyFetcher` itself is not awaitable; you instantiate it directly and then call its async methods.","cause":"Forgetting to use `await` with an asynchronous method or directly instantiating an async class without `async with` or `await` where expected.","error":"TypeError: object of type 'AsyncKeyFetcher' is not awaitable"},{"fix":"Ensure the `audience` parameter passed to `jwt.decode()` exactly matches the `aud` claim in the JWT. For production, never set `verify_aud=False`.","cause":"The audience claim in the JWT does not match the `audience` parameter provided to `jwt.decode()`, or no `audience` was provided.","error":"jwt.exceptions.InvalidAudienceError: Invalid audience"},{"fix":"Ensure the `issuer` parameter passed to `jwt.decode()` exactly matches the `iss` claim in the JWT. For production, never set `verify_iss=False`.","cause":"The issuer claim in the JWT does not match the `issuer` parameter provided to `jwt.decode()`, or no `issuer` was provided.","error":"jwt.exceptions.InvalidIssuerError: Invalid issuer"}]}