Let’s Talk About JWT
Hello!
Disclaimer
@jesstemporal
jesstemporal.com
@jesstemporal
jesstemporal.com
JWT
"Jot"
@jesstemporal
jesstemporal.com
JWT
JSON Object Signing and Encryption - JOSE
@jesstemporal
jesstemporal.com
RFC 7519
@jesstemporal
jesstemporal.com
Usually is a standardized string that represents information
@jesstemporal
jesstemporal.com
JSON Web Token
@jesstemporal
jesstemporal.com
JSON Web Token
@jesstemporal
jesstemporal.com
JSON Web Token
@jesstemporal
jesstemporal.com
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiZ2l2ZW5fbmFtZSI6Ikplc3NpY2EiLCJmYW1pbHlfbmFtZSI6IlRlbXBvcmFsIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiamVzc3RlbXBvcmFsIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE1NTIzMDU3MTB9.LmUNPW9fSAqVTGEEFW0yrsD9eooyRv_VPB3r6tCWkRc
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiZ2l2ZW5fbmFtZSI6Ikplc3NpY2EiLCJmYW1pbHlfbmFtZSI6IlRlbXBvcmFsIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiamVzc3RlbXBvcmFsIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE1NTIzMDU3MTB9.LmUNPW9fSAqVTGEEFW0yrsD9eooyRv_VPB3r6tCWkRc
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiZ2l2ZW5fbmFtZSI6Ikplc3NpY2EiLCJmYW1pbHlfbmFtZSI6IlRlbXBvcmFsIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiamVzc3RlbXBvcmFsIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE1NTIzMDU3MTB9.LmUNPW9fSAqVTGEEFW0yrsD9eooyRv_VPB3r6tCWkRc
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiZ2l2ZW5fbmFtZSI6Ikplc3NpY2EiLCJmYW1pbHlfbmFtZSI6IlRlbXBvcmFsIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiamVzc3RlbXBvcmFsIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE1NTIzMDU3MTB9.LmUNPW9fSAqVTGEEFW0yrsD9eooyRv_VPB3r6tCWkRc
@jesstemporal
jesstemporal.com
{
"alg": "HS256",
"typ": "JWT"
}
The header
@jesstemporal
jesstemporal.com
{
"sub": "1234567890",
"given_name": "Jessica",
"family_name": "Temporal",
"preferred_username": "jesstemporal",
"iat": 1516239022,
"exp": 1552305710
}
The Payload
@jesstemporal
jesstemporal.com
{
"sub": "1234567890",
"iss": "https://jtemporal.com",
"iat": 1516239022,
"exp": 1552305710
}
Reserved claims
@jesstemporal
jesstemporal.com
{
"given_name": "Jessica",
"family_name": "Temporal",
"preferred_username": "jesstemporal"
}
Public claims
@jesstemporal
jesstemporal.com
{
"anything": "you want",
"really": "anything"
}
Private claims
Keep it small,
only relevant data
@jesstemporal
jesstemporal.com
@jesstemporal
jesstemporal.com
HMACSHA256(
encodeBase64(header) + "." +
encodeBase64(payload),
"your-256-bit-secret"
)
The Signature
@jesstemporal
jesstemporal.com
HMACSHA256(
encodeBase64(header) + "." +
encodeBase64(payload),
"nPilVwFjcF0v5NL5YT1xsiwRJCGqM1do"
)
The Signature
Symmetrical algorithm
🤫
@jesstemporal
jesstemporal.com
Asymmetrical algorithm
🔑🗝
@jesstemporal
jesstemporal.com
JSON Web Key
@jesstemporal
jesstemporal.com
RFC 7517
@jesstemporal
jesstemporal.com
@jesstemporal
jesstemporal.com
JWK
{
"keys": [{
"alg": "RS256",
"kty": "RSA",
"use": "sig",
"n": "uEOPrkjGKxE...YIwS5ZoDQ",
"e": "AQAB",
"kid": "n6OFo...9cl9",
"x5t": "ET...rQA",
"x5c": ["MIIDDTCCAf...OaeyleoS0="]
}]
}
JWTs in Python
with PyJWT
@jesstemporal
jesstemporal.com
import jwt
token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI0MjQyIiwibmFtZSI6Ikplc3NpY2EgVGVtcG9yYWwiLCJuaWNrbmFtZSI6Ikplc3MifQ.izbq1mT_GXp-39o-JEm1i1W1FcYBIaX3a5c4ZwRzXhE'
jwt.decode(
token,
key='my_super_secret',
algorithms=['HS256', ]
)
import jwt
token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI0MjQyIiwibmFtZSI6Ikplc3NpY2EgVGVtcG9yYWwiLCJuaWNrbmFtZSI6Ikplc3MifQ.izbq1mT_GXp-39o-JEm1i1W1FcYBIaX3a5c4ZwRzXhE'
jwt.decode(
token,
key='my_super_secret',
algorithms=['HS256', ]
)
# {"sub": "4242", "name": "Jessica Temporal", "nickname": "Jess"}
import jwt
token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI0MjQyIiwibmFtZSI6Ikplc3NpY2EgVGVtcG9yYWwiLCJuaWNrbmFtZSI6Ikplc3MifQ.izbq1mT_GXp-39o-JEm1i1W1FcYBIaX3a5c4ZwRzXhE'
jwt.get_unverified_header(token)
import jwt
token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI0MjQyIiwibmFtZSI6Ikplc3NpY2EgVGVtcG9yYWwiLCJuaWNrbmFtZSI6Ikplc3MifQ.izbq1mT_GXp-39o-JEm1i1W1FcYBIaX3a5c4ZwRzXhE'
jwt.get_unverified_header(token)
# {'typ': 'JWT', 'alg': 'RS256'}
import jwt
token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI0MjQyIiwibmFtZSI6Ikplc3NpY2EgVGVtcG9yYWwiLCJuaWNrbmFtZSI6Ikplc3MifQ.izbq1mT_GXp-39o-JEm1i1W1FcYBIaX3a5c4ZwRzXhE'
jwt.get_unverified_header(token)
# {'typ': 'JWT', 'alg': 'RS256'}
header_data = jwt.get_unverified_header(token)
header_data['alg'] == 'HS256'
# True
import jwt
token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI0MiIsIm5hbWUiOiJKZXNzIFRlbXBvcmFsIiwiZXhwIjoxNTE2MjM5MDIyfQ.uqeQ60enLaCQEZ-7C0d_cgQSrWfgXRQuoB1LZD0j06E'
jwt.decode(
token,
key='my_super_secret',
algorithms=['HS256', ]
)
import jwt
from cryptography.hazmat.primitives import serialization
token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI0MjQyIiwibmFtZSI6Ikplc3NpY2EgVGVtcG9yYWwiLCJuaWNrbmFtZSI6Ikplc3MifQ.HgHJPl6b5W0CiDz4cNuyRcs5B3KgaoRbMvZBgCkcXOSOCAc0m7R10tSm6d86u8oW8NgzGoIAlKxBw0CIPhdx5N7MWTE2gshzQqhuq5MB9tNX1pYrLsiOMbibeMasvcf97Kd3JiLAzPPJe6XXB4PNL4h_4RcW6aCgUlRhGMPx1eRkGxAu6ndp5zzWiHQH2KVcpdVVdAwbTznLv3OLvcZqSZj_zemj__IAZPMkBBnhdjYPn-44p9-xrNmFZ9qBth4Ps1ZC1_A6lH77Mi1zb48Ou60SUT1-dhKLU09yY3IX8Pas6xtH6NbZ-e3FxjofO_OL47p25CvdqMYW50JVit2tjU6yzaoXde8JV3J40xuQqwZeP6gsClPJTdA-71PBoAYbjz58O-Aae8OlxfWZyPsyeCPQhog5KjwqsgHUQZp2zIE0Y50CEfoEzsSLRUbIklWNSP9_Vy3-pQAKlEpft0F-xP-fkSf9_AC4-81gVns6I_j4kSuyuRxlAJBe3pHi-yS2'
import jwt
from cryptography.hazmat.primitives import serialization
token = 'eyJ0eXAiOiJK...81gVns6I_j4kSuyuRxlAJBe3pHi-yS2'
public_key = open('.ssh/id_rsa.pub', 'r').read()
import jwt
from cryptography.hazmat.primitives import serialization
token = 'eyJ0eXAiOiJK...81gVns6I_j4kSuyuRxlAJBe3pHi-yS2'
public_key = open('.ssh/id_rsa.pub', 'r').read()
key = serialization.load_ssh_public_key(public_key.encode())
import jwt
from cryptography.hazmat.primitives import serialization
token = 'eyJ0eXAiOiJK...81gVns6I_j4kSuyuRxlAJBe3pHi-yS2'
public_key = open('.ssh/id_rsa.pub', 'r').read()
key = serialization.load_ssh_public_key(public_key.encode())
jwt.decode(jwt=token, key=key, algorithms=['RS256', ])
# {'sub': '4242', 'name': 'Jessica Temporal', 'nickname': 'Jess'}
Where to find JWTs?
@jesstemporal
jesstemporal.com
Access token
@jesstemporal
jesstemporal.com
RFC 9068
@jesstemporal
jesstemporal.com
ID token
@jesstemporal
jesstemporal.com
How to be safer with JWTs
@jesstemporal
jesstemporal.com
Don't store JWTs in local storage
@jesstemporal
jesstemporal.com
Don't verify JWTs in the front end
@jesstemporal
jesstemporal.com
Don't put sensitive data in the JWT
@jesstemporal
jesstemporal.com
Tools
@jesstemporal
jesstemporal.com
@jesstemporal
jesstemporal.com
@jesstemporal
jesstemporal.com
Questions?!
PyLadies Toronto - Let’s Talk About JWT
By Jessica Temporal
PyLadies Toronto - Let’s Talk About JWT
JSON Web Tokens, or JWTs for short, are all over the web. They can be used to track bits of information about a user in a very compact way and can be used in APIs for authorization purposes. Join me and learn what JWTs are, what problems it resolves, and how you can use JWTs on your applications.
- 331