Package: pyjwt-key-fetcher
pyjwt-key-fetcherAsync library to fetch JWKs for JWT tokens.This library is intended to be used together withPyJWTto automatically verify keys signed by
OpenID Connect providers. It retrieves theiss(issuer) and thekid(key ID) from
the JWT, fetches the.well-known/openid-configurationfrom the issuer to find out thejwks_uriand fetches that to find the right key.This should give similar ability to verify keys as for examplehttps://jwt.io/, where you can just paste in a token, and it will
automatically reach out and retrieve the key for you.TheAsyncKeyFetcherprovided by this library acts as an improved async replacement forPyJWKClient.InstallationThe package is available on PyPI:pipinstallpyjwt-key-fetcherUsageExampleimportasyncioimportjwtfrompyjwt_key_fetcherimportAsyncKeyFetcherasyncdefmain():fetcher=AsyncKeyFetcher()# Token and options copied from# https://pyjwt.readthedocs.io/en/2.6.0/usage.html#retrieve-rsa-signing-keys-from-a-jwks-endpointtoken="eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik5FRTFRVVJCT1RNNE16STVSa0ZETlRZeE9UVTFNRGcyT0Rnd1EwVXpNVGsxUWpZeVJrUkZRdyJ9.eyJpc3MiOiJodHRwczovL2Rldi04N2V2eDlydS5hdXRoMC5jb20vIiwic3ViIjoiYVc0Q2NhNzl4UmVMV1V6MGFFMkg2a0QwTzNjWEJWdENAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vZXhwZW5zZXMtYXBpIiwiaWF0IjoxNTcyMDA2OTU0LCJleHAiOjE1NzIwMDY5NjQsImF6cCI6ImFXNENjYTc5eFJlTFdVejBhRTJINmtEME8zY1hCVnRDIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.PUxE7xn52aTCohGiWoSdMBZGiYAHwE5FYie0Y1qUT68IHSTXwXVd6hn02HTah6epvHHVKA2FqcFZ4GGv5VTHEvYpeggiiZMgbxFrmTEY0csL6VNkX1eaJGcuehwQCRBKRLL3zKmA5IKGy5GeUnIbpPHLHDxr-GXvgFzsdsyWlVQvPX2xjeaQ217r2PtxDeqjlf66UYl6oY6AqNS8DH3iryCvIfCcybRZkc_hdy-6ZMoKT6Piijvk_aXdm7-QQqKJFHLuEqrVSOuBqqiNfVrG27QzAPuPOxvfXTVLXL2jek5meH6n-VWgrBdoMFH93QEszEDowDAEhQPHVs0xj7SIzA"key_entry=awaitfetcher.get_key(token)token=jwt.decode(jwt=token,options={"verify_exp":False},audience="https://expenses-api",**key_entry)print(token)if__name__=="__main__":asyncio.run(main())OptionsLimiting issuersYou can limit the issuers you allow fetching keys from by setting thevalid_issuerswhen creating theAsyncKeyFetcher, like this:AsyncKeyFetcher(valid_issuers=["https://example.com"])Adjusting cachingTheAsyncKeyFetcherwill by default cache data for up to 32 different issuers with a
TTL of 3600 seconds (1 hour) each. This means that in case of key-revocation, the key
will be trusted for up to 1 hour after it was removed from the JWKs.If a previously unseen kid for an already seen issuer is seen, it will trigger a
re-fetch of the JWKs, provided they have not been fetched in the past 5 minutes, in
order to rather quickly react to new keys being published.The amount of issuers to cache data for, as well as the cache time for the data can be
adjusted like this:AsyncKeyFetcher(cache_maxsize=10,cache_ttl=2*60*60)The minimum interval for checking for new keys can for now not be adjusted.Loading configuration from a custom pathYou can change from which path the configuration is loaded from the issuer (iss). By
default, the configuration is assumed to be an OpenID Connect configuration and to be
loaded from/.well-known/openid-configuration. As long as the configuration contains ajwks_uriyou can change the configuration to be loaded from a custom path.You can override the config path when creating theAsyncKeyFetcherlike this:AsyncKeyFetcher(config_path="/.well-known/dataspace/party-configuration.json")Using static configurationIf you use an issuer that does not provide a configuration (they are for example missing
the/.well-known/openid-configuration), you can create a static configuration to use
for that issuer instead and in it specify thejwks_urilike this:AsyncKeyFetcher(static_issuer_config={"https://example.com":{"jwks_uri":"https://example.com/.well-known/jwks.json",},},)Using your own HTTP ClientThe library ships with aDefaultHTTPClientthat usesaiohttpfor fetching the JSON
data; the openid-configuration and the jwks. If you want, you can write your own custom
client by inheriting from theHTTPClient. The only requirement is that it implements
an async function to fetch JSON from a given URL and return it as a dictionary.