jpadilla / pyjwt

JSON Web Token implementation in Python
https://pyjwt.readthedocs.io
MIT License
5.08k stars 679 forks source link

PyJWKClient doesn't support custom SSL contexts #789

Closed apastel closed 1 year ago

apastel commented 2 years ago

PyJWKClient doesn't support custom SSL contexts when calling fetch_data() to get the JWK set.

Expected Result

get_signing_key_from_jwt() could accept a SSLContext as a parameter to support authorization servers that may require custom SSL configurations, for example a server in a test environment that uses self-signed certs or requires a custom CA bundle.

Actual Result

For example, attempting get_signing_key_from_jwt() in a test environment that uses self-signed certs raises urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1129)>

Monkeypatched Solution

from jwt import PyJWKClient

def get_signing_key(encoded_jwt):
    PyJWKClient.fetch_data = fetch_data_ssl_verify
    jwk_client = PyJWKClient("https://acme.auth.com")
    signing_key = jwk_client.get_signing_key_from_jwt(encoded_jwt)
    return signing_key.key

def fetch_data_ssl_verify(self):
    import urllib.request
    import json
    import ssl

    ctx = ssl.create_default_context()
    ctx.load_verify_locations(cafile="/opt/certs/rootCA.pem")
    with urllib.request.urlopen(self.uri, context=ctx) as response:
        return json.load(response)

get_signing_key(encoded_jwt)

As shown, it's possible to pass a context to urllib.request.urlopen to allow specifying a custom SSLContext to enable working with servers that might be in a development environment or otherwise non-conforming to the default SSL options.

github-actions[bot] commented 1 year ago

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

ChrisMeeusen commented 1 year ago

Was this ever implemented? I"m running into this same issue because my corporate FW is doing SSL decryption. Otherwise I can look to another library.

apastel commented 1 year ago

@ChrisMeeusen Not that I know of. I'm not sure why it didn't get a response. I'm currently using my monkeypatch solution above. Maybe they ignored it because there's that workaround.

ChrisMeeusen commented 1 year ago

@ChrisMeeusen Not that I know of. I'm not sure why it didn't get a response. I'm currently using my monkeypatch solution above. Maybe they ignored it because there's that workaround.

Thanks for the response, when you say you're using the monkeypatch solution does that mean you basically pulled down all the source code for this library and build it along side your application? There is no way to just update that single file right? Sorry I'm pretty new to Python.

apastel commented 1 year ago

@ChrisMeeusen Thankfully no, you don't have to re-build the library. In Python you can essentially replace a library function by redefining it. So the code that I've shown above is all that's needed.

The top two answers here are a good reference: https://stackoverflow.com/questions/5626193/what-is-monkey-patching

Ilnur786 commented 10 months ago

I met the same issue and found that PyJWKClient receives "ssl_context" parameter.

ssl_ctx = ssl.create_default_context()
ssl_ctx.load_verify_locations(cafile="/opt/certs/rootCA.pem")

PyJWKClient("https://acme.auth.com", ssl_context=ssl_ctx)

That solves this problem

apastel commented 10 months ago

Ah, excellent. Looks like this feature was added in this merge request and then released in 2.8.0. Thanks for pointing that out! https://github.com/jpadilla/pyjwt/pull/891