JWT in Python

JWT stands for JSON Web Token, which is a standard that defines how to send JSON objects compactly.

The data in a JWT can be validated at any given time since the token is digitally signed.

The JWT has three parts separated by dots .: Header, Payload, and Signature.

Header

The Header defines the information about the JSON object.

In this case, we are saying this is a JWT token and its signature algorithm, HS256.

{
  "alg": "HS256",
  "typ": "JWT"
}

Payload

The Payload is a JSON object with information about the entity, usually used for the authenticated user info.

We can have three types of Claims: Registered, Public, and Private.

The most common Registered Claims are iss (issuer), exp (expiration time), and sub (subject).

The Public Claims are the ones we use in our applications and you can define them as you need.

Finallt, Private claims are for sharing info between applications.

DO NOT store sensitive information in your tokens.

Here is an example of a valid token:

{
  "sub": "000000",
  "name": "Admin",
  "admin": true
}

Signature

The signature is simply the concatenation of both the Header and Payload, hashed using base64UrlEncode.

It’s important to notice the secret key to make it more secure.

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

Final Result

The final result is a token with three sections separated by a dot .

The first section is the hashed header, then the payload, and finally the signature.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Implementing JWT in Python

To implement JWT in Python we are going to use the lib PyJWT.

Install it using pip as follows:

pip install PyJWT==2.1.0

Then we are going to import it as jwt.

As explained before, we are going to need a secret key, the more random the better as you can see defined in the variable JWT_SECRET_KEY.

Define the algorithm, as you can see in the JWT_ALGORITHM variable.

And finally, define for how long the token will be valid, in the example below it will last 2 days (60 minutes 24 hours 2 days).

The function create_jwt_token receives a username and role that will be assigned to sub and role in our token.

The exp value will be calculated by using the datetime and timedelta.

We can then call jwt.encode passing the jwt_payload, the secret key, and the algorithm of our choice.

The result will be a token that will expire in two days.

Then we create another function check_jwt_token that expects a token as a string.

We call jwt.decode from PyJWT, pass the token, the secret key, and the algorithm to have the info back in plain values (not hashed).

This way we can recover the values of username, role, and expiration.

Then we check if time.time() < expiration:, this will return true if the token is not expired.

Then we make a second check to match the username with one we might have in our database.

The function check_jwt_username(username) is a generic function that simply takes the username and looks for it in a user table in a database, you could implement it in any way you need.

If the token is not valid, an Exception will be thrown and the code will return False.

If the token has expired or if the username is not found in the database, the function will also return False.

import jwt
from datetime import datetime, timedelta
import time

JWT_SECRET_KEY = "MY_SUPER_SECRET_KEY"
JWT_ALGORITHM = "HS256"
JWT_EXPIRATION_TIME_MINUTES = 60 * 24 * 2

# Create access JWT token
def create_jwt_token(username, role):
    expiration = datetime.utcnow() + timedelta(minutes=JWT_EXPIRATION_TIME_MINUTES)
    jwt_payload = {"sub": username, "role": role, "exp": expiration}
    jwt_token = jwt.encode(jwt_payload, JWT_SECRET_KEY, algorithm=JWT_ALGORITHM)

    return jwt_token

# Check whether JWT token is correct
def check_jwt_token(token):
    try:
        jwt_payload = jwt.decode(token, JWT_SECRET_KEY, algorithms=JWT_ALGORITHM)
        username = jwt_payload.get("sub")
        role = jwt_payload.get("role")
        expiration = jwt_payload.get("exp")
        if time.time() < expiration:
            is_valid = check_jwt_username(username)
            if is_valid:
                return True
            else:
                return False
        else:
            return False
    except Exception as e:
        return False

This is the most generic and simple way to work with JWT tokens in Python.

One could use this to implement JWT in any framework, like Flask or FastAPI.