Skip to main content

Command Palette

Search for a command to run...

Activity 46: Documentation of Python JWT

Published
5 min readView as Markdown

What is JWT and Its Importance?

JWT (JSON Web Token) is an open standard (RFC 7519) used for securely transmitting information between parties as a JSON object. It is commonly used for authentication and authorization in web applications. The main advantage of using JWT is that it enables the stateless authentication of users, meaning the server doesn't need to store any session information on the server-side. The information about the user is encoded and stored within the JWT itself.

Structure of JWT:

A JWT consists of three parts:

  1. Header – Contains information about how the JWT is signed. It typically looks like:

     {
       "alg": "HS256", 
       "typ": "JWT"
     }
    
    • alg: The algorithm used for signing the token (e.g., HS256).

    • typ: The type of token (usually JWT).

  2. Payload – Contains the claims. Claims are statements about an entity (typically, the user) and additional data. For example, it can hold the user’s ID, roles, or expiration time:

     {
       "sub": "1234567890",
       "name": "John Doe",
       "iat": 1516239022
     }
    
    • sub: Subject (usually the user ID).

    • iat: Issued at timestamp.

  3. Signature – A cryptographic signature created using the encoded header, payload, and a secret key. This ensures that the token has not been altered. It is created by:

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

    The signature allows the server to verify that the sender of the JWT is who it says it is and to ensure the message wasn’t tampered with.

Importance of JWT:

  1. Stateless Authentication: Since the user information is encoded within the token, the server doesn't need to store session data. This improves scalability and performance.

  2. Security: JWTs can be signed and optionally encrypted. The signed JWT ensures that the data cannot be tampered with.

  3. Cross-Domain Authentication: JWTs can be used for Single Sign-On (SSO) applications across different domains.

  4. Compact and URL-safe: JWTs are compact and can be transmitted as URL query parameters, inside HTTP headers, or within cookies.

Steps to Implement JWT Authentication in Flask

Let's walk through the steps to create a Flask application that uses JWT for user authentication. We will need the following routes:

  1. POST /register – To register a new user.

  2. POST /login – To authenticate and get a JWT.

  3. GET /get-jwt – To get the JWT details (if valid).

  4. POST /set-jwt – To set a JWT (this can simulate storing a JWT in a session or cookie).

Step 1: Install Dependencies

First, you need to install the necessary libraries:

pip install Flask PyJWT
  • Flask: A web framework for building the app.

  • PyJWT: A library to create and verify JWT tokens.

Step 2: Create the Flask App

Now, let's create the Flask app, configure JWT, and define the necessary routes.

from flask import Flask, request, jsonify, make_response
import jwt
import datetime
from werkzeug.security import generate_password_hash, check_password_hash

app = Flask(__name__)

# Secret key for JWT encoding and decoding
app.config['SECRET_KEY'] = 'your_secret_key'

# In-memory user storage for simplicity
users = {}

# Route 1: Register a new user (POST /register)
@app.route('/register', methods=['POST'])
def register():
    data = request.get_json()
    username = data.get('username')
    password = data.get('password')

    if username in users:
        return jsonify({"message": "User already exists!"}), 400

    hashed_password = generate_password_hash(password)
    users[username] = hashed_password
    return jsonify({"message": "User registered successfully!"}), 201

# Route 2: User login (POST /login) - Create JWT Token
@app.route('/login', methods=['POST'])
def login():
    data = request.get_json()
    username = data.get('username')
    password = data.get('password')

    # Check if user exists
    if username not in users:
        return jsonify({"message": "User not found!"}), 404

    # Check password
    if not check_password_hash(users[username], password):
        return jsonify({"message": "Invalid password!"}), 401

    # Create JWT token
    token = jwt.encode({
        'sub': username,
        'iat': datetime.datetime.utcnow(),
        'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=1)
    }, app.config['SECRET_KEY'], algorithm='HS256')

    return jsonify({"token": token})

# Route 3: Get JWT (GET /get-jwt)
@app.route('/get-jwt', methods=['GET'])
def get_jwt():
    token = request.headers.get('Authorization')  # e.g. 'Bearer <token>'
    if not token:
        return jsonify({"message": "Token is missing!"}), 400

    try:
        token = token.split()[1]  # Get token from "Bearer <token>"
        decoded_token = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'])
        return jsonify({"message": "Token is valid", "payload": decoded_token})
    except jwt.ExpiredSignatureError:
        return jsonify({"message": "Token has expired!"}), 401
    except jwt.InvalidTokenError:
        return jsonify({"message": "Invalid token!"}), 401

# Route 4: Set JWT (POST /set-jwt)
@app.route('/set-jwt', methods=['POST'])
def set_jwt():
    data = request.get_json()
    token = data.get('token')
    if not token:
        return jsonify({"message": "Token is missing!"}), 400
    try:
        decoded_token = jwt.decode(token, app.config['SECRET_KEY'], algorithms=['HS256'])
        return jsonify({"message": "Token is valid", "payload": decoded_token})
    except jwt.ExpiredSignatureError:
        return jsonify({"message": "Token has expired!"}), 401
    except jwt.InvalidTokenError:
        return jsonify({"message": "Invalid token!"}), 401

if __name__ == '__main__':
    app.run(debug=True)

Step 3: Code Explanation

  1. /register:

    • Takes a username and password from the request body, hashes the password using werkzeug.security's generate_password_hash, and stores the username and hashed password in an in-memory dictionary.
  2. /login:

    • Takes username and password from the request body. It checks if the user exists, then checks if the password is correct. If valid, it creates a JWT token with a 1-hour expiration (exp) and returns it in the response.
  3. /get-jwt:

    • Accepts a GET request with the token in the Authorization header (in the format Bearer <token>). It tries to decode the token using the secret key. If valid, it returns the token's payload. If the token is invalid or expired, it returns an error.
  4. /set-jwt:

    • This simulates receiving and validating a JWT token. It accepts the token in the POST request body, decodes it, and returns the decoded payload if the token is valid.

Step 4: Run the Flask Application

Save the above code to a file called app.py and run the following command:

python app.py

You can now interact with the API:

  1. Register a user:

    • Send a POST request to /register with JSON data:

        {
          "username": "jov@outlook.com",
          "password": "ramonnnns"
        }
      

  2. Login (Generate JWT):

    • Send a POST request to /login with JSON data:

        {
          "username": "jov@outlook.com",
          "password": "ramonnnns"
        }
      

  3. Get JWT details:

    • Send a GET request to /get-jwt with Authorization: Bearer <token> in the header.

  4. Set JWT:

    • Send a POST request to /set-jwt with a JSON body containing the JWT token.

https://github.com/JovRoncal/roncal_python_flask_jwt

More from this blog

Jov's Blog

48 posts