¿Cómo verificar un JWT usando Python PyJWT con un certificado PEM público?

Recientemente actualicé de PyJWT 0.4.1 a 1.0.1 y no puedo averiguar cómo verificar un JWT firmado con una clave pública.

Mi código se ve así:

import jwt cert_string = "-----BEGIN CERTIFICATE-----\nMIICITCCAYqgAwIBAgIIBEsUSxL..." token_string = "eyJhbGciOiJSUzI1NiIsImtpZCI6I..." jwt.decode(token_string, cert_string, algorithms=['RS256']) 

El error que recibo es:

 File "", line 1, in  File "~/.virtualenvs/project/lib/python2.7/site-packages/jwt/api.py", line 117, in decode key, algorithms, **kwargs) File "~/.virtualenvs/project/lib/python2.7/site-packages/jwt/api.py", line 176, in _verify_signature key = alg_obj.prepare_key(key) File "~/.virtualenvs/project/lib/python2.7/site-packages/jwt/algorithms.py", line 165, in prepare_key key = load_pem_public_key(key, backend=default_backend()) File "~/.virtualenvs/project/lib/python2.7/site-packages/cryptography/hazmat/primitives/serialization.py", line 24, in load_pem_public_key return backend.load_pem_public_key(data) File "~/.virtualenvs/project/lib/python2.7/site-packages/cryptography/hazmat/backends/multibackend.py", line 285, in load_pem_public_key return b.load_pem_public_key(data) File "~/.virtualenvs/project/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 716, in load_pem_public_key self._handle_key_loading_error() File "~/.virtualenvs/project/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 912, in _handle_key_loading_error raise ValueError("Could not unserialize key data.") ValueError: Could not unserialize key data. 

Estoy seguro de que mi cert_string y token son buenos. El siguiente código se ejecuta OK:

 from cryptography.x509 import load_pem_x509_certificate from cryptography.hazmat.backends import default_backend load_pem_x509_certificate(cert_string, default_backend()) 

Mi código que solía trabajar con 0.4.1 se veía así:

 cert_string = "".join(cert_string.strip().split("\n")[1:-1]) der = a2b_base64(cert_string) cert = DerSequence() cert.decode(der) tbsCertificate = DerSequence() tbsCertificate.decode(cert[0]) subjectPublicKeyInfo = tbsCertificate[6] pub_key = RSA.importKey(subjectPublicKeyInfo) jwt.decode(token_string, pub_key) 

Cualquier ayuda sería apreciada.

Debe pasar la clave pública en lugar del certificado completo al método de deencoding. Así que extraiga la clave del certificado para usarla como en:

 from cryptography.x509 import load_pem_x509_certificate from cryptography.hazmat.backends import default_backend cert_str = "-----BEGIN CERTIFICATE-----MIIDETCCAfm..." cert_obj = load_pem_x509_certificate(cert_str, default_backend()) public_key = cert_obj.public_key() 

y entonces:

 token_string = "eyJhbGciOiJSUzI1NiIsImtpZCI6I..." jwt.decode(token_string, public_key, algorithms=['RS256']) 

Si el archivo de clave se genera utilizando ssh-keygen -t rsa (RFC4716), puede usar el archivo directamente.

Codificar:

 import jwt pemfile = open("id_rsa", 'r') keystring = pemfile.read() pemfile.close() token = jwt.encode(payload, keystring, algorithm='RS256') 

Descodificar:

 import jwt pemfile = open("id_rsa.pub", 'r') keystring = pemfile.read() pemfile.close() payload = jwt.decode(toekn, keystring, verify=True) 

No olvide detectar errores como jwt.ExpiredSignatureError etc.

Estoy usando python 3.6

 import jwt from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization key = b"""-----BEGIN PUBLIC KEY----- MIIBI....<> -----END PUBLIC KEY-----""" public_key = serialization.load_pem_public_key(key, backend=default_backend()) print(jwt.decode(token, public_key)) 

Esto funcionó como un encanto para mí.