pyjwt-key-fetcher


Namepyjwt-key-fetcher JSON
Version 0.7.0 PyPI version JSON
download
home_pagehttps://github.com/ioxiocom/pyjwt-key-fetcher
SummaryAsync library to fetch JWKs for JWT tokens
upload_time2024-01-17 13:35:14
maintainer
docs_urlNone
authorIOXIO Ltd
requires_python>=3.8,<4.0
licenseBSD-3-Clause
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # pyjwt-key-fetcher

[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/ioxiocom/pyjwt-key-fetcher/publish.yaml)](https://github.com/ioxiocom/pyjwt-key-fetcher/actions/workflows/publish.yaml)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
[![PyPI](https://img.shields.io/pypi/v/pyjwt-key-fetcher)](https://pypi.org/project/pyjwt-key-fetcher/)
[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pyjwt-key-fetcher)](https://pypi.org/project/pyjwt-key-fetcher/)
[![License: BSD 3-Clause](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)

Async library to fetch JWKs for JWT tokens.

This library is intended to be used together with
[PyJWT](https://pyjwt.readthedocs.io/en/stable/) to automatically verify keys signed by
OpenID Connect providers. It retrieves the `iss` (issuer) and the `kid` (key ID) from
the JWT, fetches the `.well-known/openid-configuration` from the issuer to find out the
`jwks_uri` and fetches that to find the right key.

This should give similar ability to verify keys as for example
[https://jwt.io/](https://jwt.io/), where you can just paste in a token, and it will
automatically reach out and retrieve the key for you.

The `AsyncKeyFetcher` provided by this library acts as an improved async replacement for
[PyJWKClient](https://pyjwt.readthedocs.io/en/2.6.0/usage.html#retrieve-rsa-signing-keys-from-a-jwks-endpoint).

## Installation

The package is available on PyPI:

```bash
pip install pyjwt-key-fetcher
```

## Usage

### Example

```python
import asyncio

import jwt

from pyjwt_key_fetcher import AsyncKeyFetcher


async def main():
    fetcher = AsyncKeyFetcher()
    # Token and options copied from
    # https://pyjwt.readthedocs.io/en/2.6.0/usage.html#retrieve-rsa-signing-keys-from-a-jwks-endpoint
    token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik5FRTFRVVJCT1RNNE16STVSa0ZETlRZeE9UVTFNRGcyT0Rnd1EwVXpNVGsxUWpZeVJrUkZRdyJ9.eyJpc3MiOiJodHRwczovL2Rldi04N2V2eDlydS5hdXRoMC5jb20vIiwic3ViIjoiYVc0Q2NhNzl4UmVMV1V6MGFFMkg2a0QwTzNjWEJWdENAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vZXhwZW5zZXMtYXBpIiwiaWF0IjoxNTcyMDA2OTU0LCJleHAiOjE1NzIwMDY5NjQsImF6cCI6ImFXNENjYTc5eFJlTFdVejBhRTJINmtEME8zY1hCVnRDIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.PUxE7xn52aTCohGiWoSdMBZGiYAHwE5FYie0Y1qUT68IHSTXwXVd6hn02HTah6epvHHVKA2FqcFZ4GGv5VTHEvYpeggiiZMgbxFrmTEY0csL6VNkX1eaJGcuehwQCRBKRLL3zKmA5IKGy5GeUnIbpPHLHDxr-GXvgFzsdsyWlVQvPX2xjeaQ217r2PtxDeqjlf66UYl6oY6AqNS8DH3iryCvIfCcybRZkc_hdy-6ZMoKT6Piijvk_aXdm7-QQqKJFHLuEqrVSOuBqqiNfVrG27QzAPuPOxvfXTVLXL2jek5meH6n-VWgrBdoMFH93QEszEDowDAEhQPHVs0xj7SIzA"
    key_entry = await fetcher.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())
```

### Options

#### Limiting issuers

You can limit the issuers you allow fetching keys from by setting the `valid_issuers`
when creating the `AsyncKeyFetcher`, like this:

```python
AsyncKeyFetcher(valid_issuers=["https://example.com"])
```

#### Adjusting caching

The `AsyncKeyFetcher` will 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:

```python
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 path

You 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 a
`jwks_uri` you can change the configuration to be loaded from a custom path.

You can override the config path when creating the `AsyncKeyFetcher` like this:

```python
AsyncKeyFetcher(config_path="/.well-known/dataspace/party-configuration.json")
```

#### Using static configuration

If 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 the `jwks_uri` like this:

```python
AsyncKeyFetcher(
    static_issuer_config={
        "https://example.com": {
            "jwks_uri": "https://example.com/.well-known/jwks.json",
        },
    },
)
```

#### Using your own HTTP Client

The library ships with a `DefaultHTTPClient` that uses `aiohttp` for fetching the JSON
data; the openid-configuration and the jwks. If you want, you can write your own custom
client by inheriting from the `HTTPClient`. The only requirement is that it implements
an async function to fetch JSON from a given URL and return it as a dictionary.

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/ioxiocom/pyjwt-key-fetcher",
    "name": "pyjwt-key-fetcher",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8,<4.0",
    "maintainer_email": "",
    "keywords": "",
    "author": "IOXIO Ltd",
    "author_email": "",
    "download_url": "https://files.pythonhosted.org/packages/d4/f9/58a76bc363853646ea720a83703b177c45ead21728a892995c13176591c7/pyjwt_key_fetcher-0.7.0.tar.gz",
    "platform": null,
    "description": "# pyjwt-key-fetcher\n\n[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/ioxiocom/pyjwt-key-fetcher/publish.yaml)](https://github.com/ioxiocom/pyjwt-key-fetcher/actions/workflows/publish.yaml)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)\n[![PyPI](https://img.shields.io/pypi/v/pyjwt-key-fetcher)](https://pypi.org/project/pyjwt-key-fetcher/)\n[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pyjwt-key-fetcher)](https://pypi.org/project/pyjwt-key-fetcher/)\n[![License: BSD 3-Clause](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)\n\nAsync library to fetch JWKs for JWT tokens.\n\nThis library is intended to be used together with\n[PyJWT](https://pyjwt.readthedocs.io/en/stable/) to automatically verify keys signed by\nOpenID Connect providers. It retrieves the `iss` (issuer) and the `kid` (key ID) from\nthe JWT, fetches the `.well-known/openid-configuration` from the issuer to find out the\n`jwks_uri` and fetches that to find the right key.\n\nThis should give similar ability to verify keys as for example\n[https://jwt.io/](https://jwt.io/), where you can just paste in a token, and it will\nautomatically reach out and retrieve the key for you.\n\nThe `AsyncKeyFetcher` provided by this library acts as an improved async replacement for\n[PyJWKClient](https://pyjwt.readthedocs.io/en/2.6.0/usage.html#retrieve-rsa-signing-keys-from-a-jwks-endpoint).\n\n## Installation\n\nThe package is available on PyPI:\n\n```bash\npip install pyjwt-key-fetcher\n```\n\n## Usage\n\n### Example\n\n```python\nimport asyncio\n\nimport jwt\n\nfrom pyjwt_key_fetcher import AsyncKeyFetcher\n\n\nasync def main():\n    fetcher = AsyncKeyFetcher()\n    # Token and options copied from\n    # https://pyjwt.readthedocs.io/en/2.6.0/usage.html#retrieve-rsa-signing-keys-from-a-jwks-endpoint\n    token = \"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik5FRTFRVVJCT1RNNE16STVSa0ZETlRZeE9UVTFNRGcyT0Rnd1EwVXpNVGsxUWpZeVJrUkZRdyJ9.eyJpc3MiOiJodHRwczovL2Rldi04N2V2eDlydS5hdXRoMC5jb20vIiwic3ViIjoiYVc0Q2NhNzl4UmVMV1V6MGFFMkg2a0QwTzNjWEJWdENAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vZXhwZW5zZXMtYXBpIiwiaWF0IjoxNTcyMDA2OTU0LCJleHAiOjE1NzIwMDY5NjQsImF6cCI6ImFXNENjYTc5eFJlTFdVejBhRTJINmtEME8zY1hCVnRDIiwiZ3R5IjoiY2xpZW50LWNyZWRlbnRpYWxzIn0.PUxE7xn52aTCohGiWoSdMBZGiYAHwE5FYie0Y1qUT68IHSTXwXVd6hn02HTah6epvHHVKA2FqcFZ4GGv5VTHEvYpeggiiZMgbxFrmTEY0csL6VNkX1eaJGcuehwQCRBKRLL3zKmA5IKGy5GeUnIbpPHLHDxr-GXvgFzsdsyWlVQvPX2xjeaQ217r2PtxDeqjlf66UYl6oY6AqNS8DH3iryCvIfCcybRZkc_hdy-6ZMoKT6Piijvk_aXdm7-QQqKJFHLuEqrVSOuBqqiNfVrG27QzAPuPOxvfXTVLXL2jek5meH6n-VWgrBdoMFH93QEszEDowDAEhQPHVs0xj7SIzA\"\n    key_entry = await fetcher.get_key(token)\n    token = jwt.decode(\n        jwt=token,\n        options={\"verify_exp\": False},\n        audience=\"https://expenses-api\",\n        **key_entry\n    )\n    print(token)\n\n\nif __name__ == \"__main__\":\n    asyncio.run(main())\n```\n\n### Options\n\n#### Limiting issuers\n\nYou can limit the issuers you allow fetching keys from by setting the `valid_issuers`\nwhen creating the `AsyncKeyFetcher`, like this:\n\n```python\nAsyncKeyFetcher(valid_issuers=[\"https://example.com\"])\n```\n\n#### Adjusting caching\n\nThe `AsyncKeyFetcher` will by default cache data for up to 32 different issuers with a\nTTL of 3600 seconds (1 hour) each. This means that in case of key-revocation, the key\nwill be trusted for up to 1 hour after it was removed from the JWKs.\n\nIf a previously unseen kid for an already seen issuer is seen, it will trigger a\nre-fetch of the JWKs, provided they have not been fetched in the past 5 minutes, in\norder to rather quickly react to new keys being published.\n\nThe amount of issuers to cache data for, as well as the cache time for the data can be\nadjusted like this:\n\n```python\nAsyncKeyFetcher(cache_maxsize=10, cache_ttl=2*60*60)\n```\n\nThe minimum interval for checking for new keys can for now not be adjusted.\n\n#### Loading configuration from a custom path\n\nYou can change from which path the configuration is loaded from the issuer (`iss`). By\ndefault, the configuration is assumed to be an OpenID Connect configuration and to be\nloaded from `/.well-known/openid-configuration`. As long as the configuration contains a\n`jwks_uri` you can change the configuration to be loaded from a custom path.\n\nYou can override the config path when creating the `AsyncKeyFetcher` like this:\n\n```python\nAsyncKeyFetcher(config_path=\"/.well-known/dataspace/party-configuration.json\")\n```\n\n#### Using static configuration\n\nIf you use an issuer that does not provide a configuration (they are for example missing\nthe `/.well-known/openid-configuration`), you can create a static configuration to use\nfor that issuer instead and in it specify the `jwks_uri` like this:\n\n```python\nAsyncKeyFetcher(\n    static_issuer_config={\n        \"https://example.com\": {\n            \"jwks_uri\": \"https://example.com/.well-known/jwks.json\",\n        },\n    },\n)\n```\n\n#### Using your own HTTP Client\n\nThe library ships with a `DefaultHTTPClient` that uses `aiohttp` for fetching the JSON\ndata; the openid-configuration and the jwks. If you want, you can write your own custom\nclient by inheriting from the `HTTPClient`. The only requirement is that it implements\nan async function to fetch JSON from a given URL and return it as a dictionary.\n",
    "bugtrack_url": null,
    "license": "BSD-3-Clause",
    "summary": "Async library to fetch JWKs for JWT tokens",
    "version": "0.7.0",
    "project_urls": {
        "Homepage": "https://github.com/ioxiocom/pyjwt-key-fetcher",
        "Repository": "https://github.com/ioxiocom/pyjwt-key-fetcher"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "67383e51e6f884950cf896ddf5ca52ced3909be8d53fc42adf934996fa8fd6ba",
                "md5": "5008f00dffa1ff98a577845f08c70442",
                "sha256": "9582343e6a12c6825e8ea18b93c42ea48ede3877191cd688ac2f560364c13cb2"
            },
            "downloads": -1,
            "filename": "pyjwt_key_fetcher-0.7.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "5008f00dffa1ff98a577845f08c70442",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8,<4.0",
            "size": 16261,
            "upload_time": "2024-01-17T13:35:12",
            "upload_time_iso_8601": "2024-01-17T13:35:12.776268Z",
            "url": "https://files.pythonhosted.org/packages/67/38/3e51e6f884950cf896ddf5ca52ced3909be8d53fc42adf934996fa8fd6ba/pyjwt_key_fetcher-0.7.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "d4f958a76bc363853646ea720a83703b177c45ead21728a892995c13176591c7",
                "md5": "4008dab2e02d30a6b462011cf2124204",
                "sha256": "8a4a608b9b5fa4ea56d9985ed596286405ec297a0b40141943356b3e63da7dbd"
            },
            "downloads": -1,
            "filename": "pyjwt_key_fetcher-0.7.0.tar.gz",
            "has_sig": false,
            "md5_digest": "4008dab2e02d30a6b462011cf2124204",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8,<4.0",
            "size": 14471,
            "upload_time": "2024-01-17T13:35:14",
            "upload_time_iso_8601": "2024-01-17T13:35:14.450975Z",
            "url": "https://files.pythonhosted.org/packages/d4/f9/58a76bc363853646ea720a83703b177c45ead21728a892995c13176591c7/pyjwt_key_fetcher-0.7.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-01-17 13:35:14",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "ioxiocom",
    "github_project": "pyjwt-key-fetcher",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "pyjwt-key-fetcher"
}
        
Elapsed time: 0.17493s