pyjwt
pyjwt copied to clipboard
PyJWK doesn't support RSA-OAEP algorithm
Using a hosted KeyCloak instance from https://www.cloud-iam.com/ which sets its enc
public cert to use RSA-OAEP
causes PyJWKClient
to throw an exception (raised by PyJWK
constructor).
Expected Result
I don't know the ins and outs of it, but either the RSA-OAEP
algorithm should be supported or the enc
cert ignored (the sig
one is RSA256
).
Actual Result
Traceback (most recent call last):
File "/home/flyte/dev/ascender/ascender-api/test.py", line 8, in <module>
PyJWKSet(certs_from_keycloak["keys"])
File "/home/flyte/.cache/pypoetry/virtualenvs/ascender-api-35481XGP-py3.10/lib/python3.10/site-packages/jwt/api_jwk.py", line 87, in __init__
self.keys.append(PyJWK(key))
File "/home/flyte/.cache/pypoetry/virtualenvs/ascender-api-35481XGP-py3.10/lib/python3.10/site-packages/jwt/api_jwk.py", line 50, in __init__
raise PyJWKError("Unable to find a algorithm for key: %s" % self._jwk_data)
jwt.exceptions.PyJWKError: Unable to find a algorithm for key: {'kid': 'A2MJgrKnftrPyUXS-FNN4g0spwz1H89gPTAzjb4u91o', 'kty': 'RSA', 'alg': 'RSA-OAEP', 'use': 'enc', 'n': 'xTT6GOIMi7GXWUNQ4ZoFQuHihNVnRxx9Y9hAcvV6ZO-OiT9dcLqVIlhDckf7yVOfitMG_qZkhIzaOBWNWJZK1_zaeFCv_GQPPEVi_JafLUKz6AAaMdqiFuKfDyoAecOJWc0ar4autehQMpuRLh8POMmrnNMLolWqEauYmu_ajT9eA99hcseahDDhPWgGuSc0mFNS5YcjyIaoKfwWWkvtfqKNBEzf_EnbSsAibQWXUvVCRRLSNdCrImdR-FdprpudQs7sTetP5lU2aP0ChpM8GemidA5ZieNdykW1lVi0Sa6R1gkGzhL03LYzaPzgc8RMJQtaZg93EuSQLs66uKM3-w', 'e': 'AQAB', 'x5c': ['MIICnzCCAYcCBgF+Q6te9zANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhhc2NlbmRlcjAeFw0yMjAxMTAxMTA1MTFaFw0zMjAxMTAxMTA2NTFaMBMxETAPBgNVBAMMCGFzY2VuZGVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxTT6GOIMi7GXWUNQ4ZoFQuHihNVnRxx9Y9hAcvV6ZO+OiT9dcLqVIlhDckf7yVOfitMG/qZkhIzaOBWNWJZK1/zaeFCv/GQPPEVi/JafLUKz6AAaMdqiFuKfDyoAecOJWc0ar4autehQMpuRLh8POMmrnNMLolWqEauYmu/ajT9eA99hcseahDDhPWgGuSc0mFNS5YcjyIaoKfwWWkvtfqKNBEzf/EnbSsAibQWXUvVCRRLSNdCrImdR+FdprpudQs7sTetP5lU2aP0ChpM8GemidA5ZieNdykW1lVi0Sa6R1gkGzhL03LYzaPzgc8RMJQtaZg93EuSQLs66uKM3+wIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBXmX39VyMNsmWn6I5myY9YZbHZEaYJ7xZ4eRbkrNN6znx8ar1YdI5zqpp2J91SL7Ni6IVEqHPPkwh/JI6KcEK5mO4bQxLY5YJb4h0z00jFoyn5IxDkFUgbgWQxRanyeSh0iQDHz0J6hbgjzTft25y87KxrdvJDQ8lxoDuQgSogrw/EAl0hMnauS1m87pjkzhhsYDBRwy0G3muDEgmA1E7RAM00ec/SuDAKvwF7HFf6xgSH8YALstz34drKbkWZIiGQIub3Y4swbN3Myb+whiwCLYW1olubFkvH7anSq6d39ZdJhxXmz3rhK0YlJ9O32WHBA1w/U/4wg8YIv6DSHYGF'], 'x5t': 'WAcN3AzixLmWqoKdNhhmxilWhFU', 'x5t#S256': 'M4D1NyJsOrtsjG7tRbDs-zd7hg2tvm9kbYDS4gRO7KI'}
Reproduction Steps
import json
from jwt import PyJWKSet
certs_from_keycloak = json.loads("""{"keys":[{"kid":"JJPd3kTh6QFpJ9P-MSFZbBf43S-LRTAot4DJmwd5EQk","kty":"RSA","alg":"RS256","use":"sig","n":"yluqHNqoRdCqCmhivy_yl4dDDMI5pwg59VMz7dYQREfehxukXPhfchbAHxDhGCZjUYieV4TIRGyEBVR3zQ9ihjStYPz8bXUeWqMBSYaH8R7Xb98GeZplVKnF-OLj0fWJkoNSgPYKuSDm2KXdz2hIZ1jOPKLDqpblnnqxrL_xX-1_kEBWehJmzmS0McCOK2nm7lLWf6zoTBi-bp1x5iNl7qteHdo0UZl1DP4NVE0lYk0uGa-L6ye0pQKS77Ro3R5nURvEO0AcaXYr6wLcxYsPRiYDlOactB6WnRFKAhEgRzdp1a04tH8hquHhrdjTc_ZoZelk6ppd-3ZqGq3jMc7TWw","e":"AQAB","x5c":["MIICnzCCAYcCBgF+Q6teWDANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhhc2NlbmRlcjAeFw0yMjAxMTAxMTA1MTFaFw0zMjAxMTAxMTA2NTFaMBMxETAPBgNVBAMMCGFzY2VuZGVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyluqHNqoRdCqCmhivy/yl4dDDMI5pwg59VMz7dYQREfehxukXPhfchbAHxDhGCZjUYieV4TIRGyEBVR3zQ9ihjStYPz8bXUeWqMBSYaH8R7Xb98GeZplVKnF+OLj0fWJkoNSgPYKuSDm2KXdz2hIZ1jOPKLDqpblnnqxrL/xX+1/kEBWehJmzmS0McCOK2nm7lLWf6zoTBi+bp1x5iNl7qteHdo0UZl1DP4NVE0lYk0uGa+L6ye0pQKS77Ro3R5nURvEO0AcaXYr6wLcxYsPRiYDlOactB6WnRFKAhEgRzdp1a04tH8hquHhrdjTc/ZoZelk6ppd+3ZqGq3jMc7TWwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQB0EJ2Q8/YKMFr7JRG7IwfMo2Z5bpBluVxtnBTt6EcS+QBQ4LVvh6GmpeNPZhVJHjSb7/yFs1iDGIiJDzbffE+mXRYYfjcl02IlzwOEv+v1wVqbCWfKuZIIDZIWJgmZCJF8xUJgGt+wyv3N2lR1X9GDaCaq9Z4L69vsB+2EQ0YM64ZJf5FXlYQ3Fdaq6kEZaTXpNwR7TlvKFUYaelP0a/c8m/izzfE8dX1WJBUne9Pgnn7emfdTYWmdCAaodv97DJoc3RWQgJhdgxgK85/qDIBfI86FiM3dPWR6/FmLox4f5WIZumWuAgNXBVyvBu+qU7FbwpeS+SlpBCwZuWqoMvEP"],"x5t":"dcy5v0xWv0qvgfX3CzbukvB5TlA","x5t#S256":"tyTUdZfGEopkBZ0BYyC8IxvQL5KFCn9-Po0V4ociZiY"},{"kid":"A2MJgrKnftrPyUXS-FNN4g0spwz1H89gPTAzjb4u91o","kty":"RSA","alg":"RSA-OAEP","use":"enc","n":"xTT6GOIMi7GXWUNQ4ZoFQuHihNVnRxx9Y9hAcvV6ZO-OiT9dcLqVIlhDckf7yVOfitMG_qZkhIzaOBWNWJZK1_zaeFCv_GQPPEVi_JafLUKz6AAaMdqiFuKfDyoAecOJWc0ar4autehQMpuRLh8POMmrnNMLolWqEauYmu_ajT9eA99hcseahDDhPWgGuSc0mFNS5YcjyIaoKfwWWkvtfqKNBEzf_EnbSsAibQWXUvVCRRLSNdCrImdR-FdprpudQs7sTetP5lU2aP0ChpM8GemidA5ZieNdykW1lVi0Sa6R1gkGzhL03LYzaPzgc8RMJQtaZg93EuSQLs66uKM3-w","e":"AQAB","x5c":["MIICnzCCAYcCBgF+Q6te9zANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhhc2NlbmRlcjAeFw0yMjAxMTAxMTA1MTFaFw0zMjAxMTAxMTA2NTFaMBMxETAPBgNVBAMMCGFzY2VuZGVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxTT6GOIMi7GXWUNQ4ZoFQuHihNVnRxx9Y9hAcvV6ZO+OiT9dcLqVIlhDckf7yVOfitMG/qZkhIzaOBWNWJZK1/zaeFCv/GQPPEVi/JafLUKz6AAaMdqiFuKfDyoAecOJWc0ar4autehQMpuRLh8POMmrnNMLolWqEauYmu/ajT9eA99hcseahDDhPWgGuSc0mFNS5YcjyIaoKfwWWkvtfqKNBEzf/EnbSsAibQWXUvVCRRLSNdCrImdR+FdprpudQs7sTetP5lU2aP0ChpM8GemidA5ZieNdykW1lVi0Sa6R1gkGzhL03LYzaPzgc8RMJQtaZg93EuSQLs66uKM3+wIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBXmX39VyMNsmWn6I5myY9YZbHZEaYJ7xZ4eRbkrNN6znx8ar1YdI5zqpp2J91SL7Ni6IVEqHPPkwh/JI6KcEK5mO4bQxLY5YJb4h0z00jFoyn5IxDkFUgbgWQxRanyeSh0iQDHz0J6hbgjzTft25y87KxrdvJDQ8lxoDuQgSogrw/EAl0hMnauS1m87pjkzhhsYDBRwy0G3muDEgmA1E7RAM00ec/SuDAKvwF7HFf6xgSH8YALstz34drKbkWZIiGQIub3Y4swbN3Myb+whiwCLYW1olubFkvH7anSq6d39ZdJhxXmz3rhK0YlJ9O32WHBA1w/U/4wg8YIv6DSHYGF"],"x5t":"WAcN3AzixLmWqoKdNhhmxilWhFU","x5t#S256":"M4D1NyJsOrtsjG7tRbDs-zd7hg2tvm9kbYDS4gRO7KI"}]}""")
PyJWKSet(certs_from_keycloak["keys"])
Pretty-printed cert for your pleasure
{
"kid": "A2MJgrKnftrPyUXS-FNN4g0spwz1H89gPTAzjb4u91o",
"kty": "RSA",
"alg": "RSA-OAEP",
"use": "enc",
"n": "xTT6GOIMi7GXWUNQ4ZoFQuHihNVnRxx9Y9hAcvV6ZO-OiT9dcLqVIlhDckf7yVOfitMG_qZkhIzaOBWNWJZK1_zaeFCv_GQPPEVi_JafLUKz6AAaMdqiFuKfDyoAecOJWc0ar4autehQMpuRLh8POMmrnNMLolWqEauYmu_ajT9eA99hcseahDDhPWgGuSc0mFNS5YcjyIaoKfwWWkvtfqKNBEzf_EnbSsAibQWXUvVCRRLSNdCrImdR-FdprpudQs7sTetP5lU2aP0ChpM8GemidA5ZieNdykW1lVi0Sa6R1gkGzhL03LYzaPzgc8RMJQtaZg93EuSQLs66uKM3-w",
"e": "AQAB",
"x5c": [
"MIICnzCCAYcCBgF+Q6te9zANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhhc2NlbmRlcjAeFw0yMjAxMTAxMTA1MTFaFw0zMjAxMTAxMTA2NTFaMBMxETAPBgNVBAMMCGFzY2VuZGVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxTT6GOIMi7GXWUNQ4ZoFQuHihNVnRxx9Y9hAcvV6ZO+OiT9dcLqVIlhDckf7yVOfitMG/qZkhIzaOBWNWJZK1/zaeFCv/GQPPEVi/JafLUKz6AAaMdqiFuKfDyoAecOJWc0ar4autehQMpuRLh8POMmrnNMLolWqEauYmu/ajT9eA99hcseahDDhPWgGuSc0mFNS5YcjyIaoKfwWWkvtfqKNBEzf/EnbSsAibQWXUvVCRRLSNdCrImdR+FdprpudQs7sTetP5lU2aP0ChpM8GemidA5ZieNdykW1lVi0Sa6R1gkGzhL03LYzaPzgc8RMJQtaZg93EuSQLs66uKM3+wIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBXmX39VyMNsmWn6I5myY9YZbHZEaYJ7xZ4eRbkrNN6znx8ar1YdI5zqpp2J91SL7Ni6IVEqHPPkwh/JI6KcEK5mO4bQxLY5YJb4h0z00jFoyn5IxDkFUgbgWQxRanyeSh0iQDHz0J6hbgjzTft25y87KxrdvJDQ8lxoDuQgSogrw/EAl0hMnauS1m87pjkzhhsYDBRwy0G3muDEgmA1E7RAM00ec/SuDAKvwF7HFf6xgSH8YALstz34drKbkWZIiGQIub3Y4swbN3Myb+whiwCLYW1olubFkvH7anSq6d39ZdJhxXmz3rhK0YlJ9O32WHBA1w/U/4wg8YIv6DSHYGF"
],
"x5t": "WAcN3AzixLmWqoKdNhhmxilWhFU",
"x5t#S256": "M4D1NyJsOrtsjG7tRbDs-zd7hg2tvm9kbYDS4gRO7KI"
}
System Information
{
"cryptography": {
"version": "36.0.1"
},
"implementation": {
"name": "CPython",
"version": "3.10.1"
},
"platform": {
"release": "5.4.0-91-generic",
"system": "Linux"
},
"pyjwt": {
"version": "2.3.0"
}
}
Seems to be affecting token validation from keycloak 16. Downgrading keycloak to version 15.0.1 solves this issue for me. Waiting for this to be fixed before upgrading keycloak.
I was running into the same problem. Since keys with algorithms I cannot handle are the same to me as non existing keys, I decided to simply ignore them. I derived a slightly adapted PyJWKClient:
class FilteredPyJWKClient(PyJWKClient):
"""
A PyJWKClient which ignores keys with unknown algorithms instead of throwing an exception.
"""
@lru_cache(maxsize=1)
def _default_algorithms(self):
return get_default_algorithms()
def fetch_data(self) -> Any:
data = super().fetch_data()
return {"keys": [key for key in data.get("keys", []) if key.get("alg", None) in self._default_algorithms()]}
I am not sure if it could be feasible to integrate this kind of behaviour via a flag during the creation of a genuine PyJWKClient or not, but I just wanted to share the solution that worked for me. As soon as this Issue is resolved I will happily switch to the "official" solution.
As a workaround you can also configure keycloak to disable the RSA-OAEP key or use a different algorithm until it is supported.
Realm->Settings->Keys->rsa-enc-generated->enabled=False
That didn't work for me @pm-coelho while using jboss/keycloak latest version
Notice that alg
is now RS256
@tiago-peres do you have the crypto optional dependency dependency installed?
@tiago-peres do you have the crypto optional dependency dependency installed?
Well spotted... I don't and using RUN pip install pyjwt[crypto]
doesn't build the image
Then tried RUN pip install cryptography
but also
that looks like a missing OS dependency, make sure you have all that crypto requires installed and on $PATH
that looks like a missing OS dependency, make sure you have all that crypto requires installed and on $PATH
you're right again... As per the documentation:
sudo apk add gcc musl-dev python3-dev libffi-dev openssl-dev cargo
it was missing libffi-dev openssl-dev cargo
. Currently building the image and will soon test again...
As a workaround you can also configure keycloak to disable the RSA-OAEP key or use a different algorithm until it is supported.
Realm->Settings->Keys->rsa-enc-generated->enabled=False
yep, that's working if we ensure the next steps I've done after! Thank you!
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
We encountered the same error while using pyjwt with keycloak. Is support for RSA-OAEP planned ?
I think the issue itself may be resolved with #762.
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