Activity 46: Documentation of Python JWT

Introduction to JWT

  • What is JWT?
    JSON Web Token (JWT) is a secure way to transmit information between parties as a JSON object, which is digitally signed to ensure data integrity and authenticity.

  • How JWT Works
    JWTs are often used in authentication and authorization systems. When a user logs in, the server creates a token containing essential user information, signed with a secret key. The user then uses this token to authenticate and access protected resources, allowing for stateless and efficient authentication.

  • Why JWT is Important
    JWTs make applications more scalable by handling authentication without storing session data on the server. They also provide better security through token expiration, ensuring that unauthorized users cannot access protected resources.

Step-by-Step Guide for Implementing JWT in Python Flask

Step 1: Set Up the Project Directory

  1. Open Command Prompt and create a new directory for the project:

      mkdir nicolas_python_flask_jwt
      cd nicolas_python_flask_jwt
    
  2. Create a Virtual Environment:

      python -m venv env
    
  3. Activate the Virtual Environment (on Windows):

      .\env\Scripts\activate
    

Step 2: Install Flask and PyJWT Libraries

With the virtual environment active, install Flask and PyJWT (a popular Python library for working with JWTs):

pip install Flask PyJWT

Step 3: Create the app.py File

In the project folder, create a new file named app.py where we’ll add the Flask routes and JWT logic.

  1. Import Libraries: We’ll need Flask, request, jsonify from Flask, and jwt for generating and verifying tokens.

  2. Create the Flask App:

      from flask import Flask, request, jsonify
      import jwt
      import datetime
    
      app = Flask(__name__)
      app.config['SECRET_KEY'] = 'your_secret_key'  # Replace with a strong secret key
    

    The SECRET_KEY is crucial for encoding and decoding JWTs securely. Replace 'your_secret_key' with a unique, strong key.

Step 4: Implement the JWT Routes

Now, I’ll add the main endpoints for /register, /login, /get-jwt, and /set-jwt.

4.1 POST /register Route

The /register endpoint allows users to create an account. For simplicity, I’ll store user data in memory.

users = {}  # A dictionary to store user data temporarily

@app.route('/register', methods=['POST'])
def register():
    data = request.json
    username = data.get('username')
    password = data.get('password')

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

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

4.2 POST /login Route

The /login endpoint authenticates the user and generates a JWT if the credentials are valid.

@app.route('/login', methods=['POST'])
def login():
    data = request.json
    username = data.get('username')
    password = data.get('password')

    if users.get(username) != password:
        return jsonify({"message": "Invalid username or password"}), 401

    token = jwt.encode({
        'username': username,
        'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=30)
    }, app.config['SECRET_KEY'], algorithm="HS256")

    return jsonify({"token": token})

This endpoint generates a JWT token with an expiration time of 30 minutes, encoded with the user’s username and our secret key.

4.3 GET /get-jwt Route

The /get-jwt route allows us to verify the token. If the token is valid, the server responds with the user’s information.

@app.route('/get-jwt', methods=['GET'])
def get_jwt():
    token = request.headers.get('Authorization')

    if not token:
        return jsonify({"message": "Token is missing!"}), 401

    try:
        data = jwt.decode(token, app.config['SECRET_KEY'], algorithms=["HS256"])
        return jsonify({"user": data['username']})
    except jwt.ExpiredSignatureError:
        return jsonify({"message": "Token has expired!"}), 401
    except jwt.InvalidTokenError:
        return jsonify({"message": "Invalid token!"}), 401

4.4 POST /set-jwt Route

In this route, I’ll create a new token and return it. This endpoint can be used for generating tokens for other services or sessions.

@app.route('/set-jwt', methods=['POST'])
def set_jwt():
    data = request.json
    username = data.get('username')

    if username not in users:
        return jsonify({"message": "User does not exist"}), 404

    token = jwt.encode({
        'username': username,
        'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=30)
    }, app.config['SECRET_KEY'], algorithm="HS256")

    return jsonify({"token": token})

Step 5: Run the Flask Application

To start the server, use the command:

python app.py

This will run the app on http://127.0.0.1:5000/

Step 6: Test the Endpoints

Using Postman or any other tool, test each endpoint:

  1. POST /register:

    • Set the request type to POST and the URL to http://127.0.0.1:5000/register.

    • In the Body, select raw and JSON format, then enter a JSON object with "username" and "password" fields.

      If the user already exists, the response will be:

  2. POST /login:

    • Send a POST request to http://127.0.0.1:5000/login with the same JSON structure as the /register endpoint.

    • The response should contain a JWT token if the credentials are correct.

      If the credentials are incorrect, you’ll see:

  3. GET /get-jwt:

    • Copy the token from the /login response.

    • Send a GET request to http://127.0.0.1:5000/get-jwt with the token in the Authorization header.

    • The server should return the username if the token is valid.

  4. POST /set-jwt:

    • Send a POST request to http://127.0.0.1:5000/set-jwt with "username" in the JSON body.

    • This will return a new JWT for the specified username.

      If the username does not exist, you’ll receive:

Step 7: Push the Project to GitHub

git init
git add .
git commit -m "Initial commit"
git remote add origin  https://github.com/MonetForProgrammingPurposes/cd-nicolas_python_flask_encryption_and_decryption.git
git push -u origin master