In this article, we are going to walkthrough a version of the raw implementation of the JWT specification in Python3. For simplicity, we will use the HMAC + SHA256 for the signing algorithm.
Let’s look at the JWT in a functional sense. There are three outputs to the JWT concatenated with a dot(“.”).
{base64_header}.{base64_payload}.{base64_signature}
When building the JWT, there are three inputs.
- the header describing the token type and the signing algorithm in JSON
- the payload describing the claims or information about the user assigned the token in JSON
- the private key that is used to sign the header and the payload
The following are the functional operations.
- Removing all non-key, non-value white spaces in the JSON message
- URL Safe Base64 encoding
- HMAC (Keyed-Hashing for Message Authentication) operation
Functional Operations
We will first look at the individual operations and bring it all together.
JSON White Space Removal
import jsoncleaned_json_str = json.dumps(
json.loads(raw_json_string),
separators = (",", ":"), # default is (",", ": ") notice the space
)
Transport Safe Encoding
import base64b64_encoded_json = base64.urlsafe_b64encode(
cleaned_json_str.encode("ascii") # convert to bytes
)# here we need to strip the offsets filled with "=" for use
#
b64_final_json = b64_encoded_json.decode("ascii").rstrip("=")
HMAC
import hmac
import hashlib
import base64secret_key_bytes = b"my_secret_key"signature_bytes = hmac.new(
secret_key_bytes,
msg = your_message_to_sign.encode("ascii"),
digestmod = hashlib.sha256,
).digest()b64_signature = base64.urlsafe_b64encode(
signature_bytes).decode("ascii").rstrip("=")
Inputs
For the illustration we will use the following header and payload JSON’s.
Header
{
"alg": "HS256",
"typ": "JWT"
}
Payload
{
"sub": "cd08769d-c6a5-43cf-be5f-14f34ecddaa2",
"name": "Your Friendly Neighbor",
"iat": 1609459200
}
Private Key
your-secret-goes-here