How to use a jwt.io provisioned token with jwcrypto?

522 views Asked by At

I am trying to use a jwt.io generated JWT within my python code using jwcrypto with some success. I am saying some success because I am able to retrieve the claims (the wrong way) without validating the signature.

Here's my code

from jwcrypto import jwt, jwk

jwtIoToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'

theJwt = jwt.JWT(jwt=jwtIoToken)
print(theJwt)
print(theJwt.token.objects)

The jwtIoToken value is taken verbatim from the jwt.io. I was expecting to be able to just do a theJwt.claims but it is set to None. My hunch is that I need to validate the signature, but I have no idea how to do it without the key for which I have no clue what jwt.io is using.

2

There are 2 answers

0
jps On BEST ANSWER

You can find the key that jwt.io uses in the right column under "VERIFY SIGNATURE". Unless you add anything different, the default value is "your-256-bit-secret".

enter image description here

When you use that value, you can verify the signature with the code below.

jwcrypto is a bit more complicated to use than pyjwt. Here you first have to initialize a JWK object and create the key from the given secret and then pass the key to the verify(key)-function:

from jwcrypto import jws, jwk

jwtIoToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
key = jwk.JWK().from_password("your-256-bit-secret")

jwstoken = jws.JWS()
jwstoken.deserialize(jwtIoToken)
jwstoken.verify(key)
payload = jwstoken.payload

print(payload.decode())
0
Guillaume On

I can suggest you to use an alternative to jwcrypto named jwskate.

jwcrypto quite convoluted imports and API make it unintuitive to use, as you have noticed, while jwskate has a more convenient and Pythonic API:

from jwskate import Jwt, SymmetricJwk

# you can access the token contents, as a dict, without verifying the signature:
jwt = Jwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c')
assert jwt.claims == {'sub': '1234567890', 'name': 'John Doe', 'iat': 1516239022}
# or you can access individual claims this way
assert jwt['sub'] == jwt.sub == '1234567890'
assert jwt['name'] == jwt.name == 'John Doe'
from datetime import datetime, timezone
assert jwt.issued_at == datetime(2018, 1, 18, 1, 30, 22, tzinfo=timezone.utc)

# if you want to verify the signature:
key = SymmetricJwk.from_bytes(b"your-256-bit-secret")
assert jwt.verify_signature(key, alg="HS256")

Disclaimer: I am the author of jwskate.