JSON Web Tokens

A JSON Web Token, or JWT, is a JSON-based open standard for creating tokens that assert some number of claims. You can learn all about this technology on the website (https://jwt.io/). In a nutshell, this type of token is comprised of three sections, separated by a dot, in the format A.B.CB is the payload, which is where we put the data and the claims. C is the signature, which is used to verify the validity of the token, and A is the algorithm used to compute the signature. AB, and C are all encoded with a URL safe Base64 encoding (which I'll refer to as Base64URL).

Base64 is a very popular binary-to-text encoding scheme that represents binary data in an ASCII string format by translating it into a radix-64 representation. The radix-64 representation uses the letters A-Z, a-z, and the digits 0-9, plus the two symbols + and / for a grand total of 64 symbols altogether. Therefore, not surprisingly, the Base64 alphabet is made up of these 64 symbols. Base64 is used, for example, to encode images attached in an email. It happens seamlessly, so the vast majority of people are completely oblivious of this fact.

The reason why a JWT is encoded using Base64URL is because of the characters + and /, which in a URL context mean space, and path separator, respectively. Therefore in the URL safe version, they are replaced with - and _. Moreover, any padding character (=), which is normally used in Base64, is stripped out, as this too has a specific meaning within a URL. 

The way this type of token works is therefore slightly different than what we are used to when we work with hashes. In fact, the information that the token carries is always visible. You just need to decode A and B to get the algorithm and the payload. However, the security lies in part C, which is a HMAC hash of the token. If you try to modify the B part by editing the payload, encoding it back to Base64, and replacing it in the token, the signature won't match any more, and therefore the token will be invalid.

This means that we can build a payload with claims such as logged in as admin, or something along those lines, and as long as the token is valid, we know we can trust that that user is actually logged in as an admin.

When dealing with JWTs, you want to make sure you have researched how to handle them safely. Things like not accepting unsigned tokens, or restricting the list of algorithms you use to encode and decode, as well as other security measures, are very important and you should take the time to investigate and learn them.

For this part of the code, you will have to have the PyJWT and cryptography Python packages installed. As always, you will find them in the requirements of the source code of this book.

Let's start with a simple example:

# tok.py
import jwt

data = {'payload': 'data', 'id': 123456789}

token = jwt.encode(data, 'secret-key')
data_out = jwt.decode(token, 'secret-key')
print(token)
print(data_out)

We define the data payload, which contains an ID and some payload data. Then, we create a token using the jwt.encode function, which takes at least the payload and a secret key, which is used to compute the signature. The default algorithm used to calculate the token is HS256. Let's see the output:

$ python tok.py
b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwYXlsb2FkIjoiZGF0YSIsImlkIjoxMjM0NTY3ODl9.WFRY-uoACMoNYX97PXXjEfXFQO1rCyFCyiwxzOVMn40'
{'payload': 'data', 'id': 123456789}

So, as you can see, the token is a binary string of Base64URL-encoded pieces of data. We have called jwt.decode, providing the correct secret key. Had we done otherwise, the decoding would have broken.

Sometimes, you might want to be able to inspect the content of the token without verifying it. You can do so by simply calling decode this way:

# tok.py
jwt.decode(token, verify=False)

This is useful, for example, when values in the token payload are needed to recover the secret key, but that technique is quite advanced so I won't be spending time on it in this context. Instead, let's see how we can specify a different algorithm for computing the signature:

# tok.py
token512 = jwt.encode(data, 'secret-key', algorithm='HS512')
data_out = jwt.decode(token512, 'secret-key', algorithm='HS512')
print(data_out)

The output is our original payload dictionary. In case you want to allow more than one algorithm in the decoding phase, you can even specify a list of them, instead of only one.

Now, while you are free to put whatever you want in the token payload, there are some claims that have been standardized, and they enable you to have a great deal of control over the token.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset