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.