Home

Team Teaching - JWT Implementation

What is JWT

JWT (JSon Web tokens) is a compact url safe means of representing claims bewtween two parties

Parts of JWT

Encoded JWT:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Decoded JWT:{ “sub”: “1234567890”, “name”: “John Doe”, “iat”: 1516239022 }

Implementing JWT into Flask Project

CORS Configuration:

The code below allows for cross origin resource sharing. This is needed for the front end to be able to access the backend when they are running on different domains. With suports_credentials set to true, credentials with requests are included allowing for authenticatin.

cors = CORS(app, supports_credentials=True)

Dynamic Allowed Origins:

The code below only allows specified origins to access the backend. Using the list of allowed origins, the code checks if the origin of the request is in the list of allowed origins. If it is, the origin is added to the response headers. If it is not, the origin is not added to the response headers.


@app.before_request
def before_request():
    allowed_origin = request.headers.get('Origin')
    if allowed_origin in ['http://localhost:4100', 'http://127.0.0.1:4100', 'https://nighthawkcoders.github.io']:
        cors._origins = allowed_origin

SameSite Attribute in set_cookie:


resp.set_cookie(
    "jwt",
    token,
    max_age=3600,
    secure=True,
    httponly=True,
    path='/',
    samesite='None'
)

Nginx Preflighted Requests Configuration:

First the code checks if the request method is OPTIONS.

If the condition is met (OPTIONS request), the following actions are taken:


if ($request_method = OPTIONS) {
    add_header "Access-Control-Allow-Credentials" "true" always;
    add_header "Access-Control-Allow-Origin"  "https://nighthawkcoders.github.io" always;
    add_header "Access-Control-Allow-Methods" "GET, POST, PUT, OPTIONS, HEAD" always;
    add_header "Access-Control-Allow-MaxAge" 600 always;
    add_header "Access-Control-Allow-Headers" "Authorization, Origin, X-Requested-With, Content-Type, Accept" always;
    return 204;
}

Installation

  1. Install JWT extension or Flask-JWT-Extended extension
pip install pyJWT
  1. Create Flask app and initialize JWT
from flask import Flask
from pyJWT import JWTManager

app = Flask(__name__)
app.config['JWT_SECRET_KEY'] = 'your-secret-key'  # Replace with a strong secret key
jwt = JWTManager(app)
  1. Create a login endpoint to generate tokens:
@app.route('/login', methods=['POST'])
def login():
    # Verify user credentials
    if verify_credentials():  # Replace with your authentication logic
        user_id = get_user_id()
        access_token = create_access_token(identity=user_id)  # JWT creation
        return jsonify({'access_token': access_token})
    else:
        return jsonify({'error': 'Invalid credentials'}), 401
  1. Protect routes with jwtrequired decorator
@app.route('/protected')
@jwt_required
def protected():
    current_user = get_jwt_identity()  # Access user information from token
    return jsonify({'message': 'Hello, {}!'.format(current_user)})

Validating JWT cookies ensures the integrity and authenticity of user sessions, guarding against tampering, expiration, and unauthorized access in web applications.

Validating a JWT takes multiple steps. Below is a simple Python script using the PyJWT library to demonstrate JWT validation.




Make sure to install the library first

pip install PyJWT

After that, run this python script using the PyJWT library to demonstrate JWT validation

import jwt
from datetime import datetime, timedelta

SECRET_KEY = 'your_secret_key_here'

def create_jwt():
    payload = {
        'user_id': 123,
        'username': 'john_doe',
        'exp': datetime.utcnow() + timedelta(hours=1)
    }
    token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')
    return token
def validate_jwt(token):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
        print("JWT Validation Successful!")
        print("Payload:", payload)
    except jwt.ExpiredSignatureError:
        print("JWT has expired. Please obtain a new token.")
    except jwt.InvalidTokenError:
        print("Invalid JWT. Authentication failed.")

if __name__ == "__main__":
    jwt_token = create_jwt()
    print("Generated JWT:", jwt_token)

    validate_jwt(jwt_token)
Generated JWT: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxMjMsInVzZXJuYW1lIjoiam9obl9kb2UiLCJleHAiOjE3MDU5NDQ5MjF9.EFt_W-nQPIn9k4IKyuVWJz-6yKgDcUTDNX9jix5AmaQ
JWT Validation Successful!
Payload: {'user_id': 123, 'username': 'john_doe', 'exp': 1705944921}

In this Python script, the jwt library is employed to handle JSON Web Tokens (JWTs) for user authentication. The create_jwt function generates a JWT with a payload containing user information, including a user ID, username, and an expiration time set to one hour from the current time. The jwt.encode function combines this payload with a secret key using the HMAC SHA256 algorithm to create a secure token.

The validate_jwt function takes a JWT as input, attempts to decode it using the same secret key, and checks for validity. If successful, it prints the decoded user details; otherwise, it handles expired or invalid tokens by raising specific exceptions. The script demonstrates the creation and validation of JWTs for secure user authentication.

JWT Cookies

Cookies are pieces of information that are used to be sent to from a server to a browser and stored on the device it has been sent to. They are then sent back to the server with data about the user’s interactions with the site which will help the server store the user’s preferences and info throughout the website. Cookies can also help keep users authenticated on servers by storing authentication tokens to the server.

Anatomy of Flask

Screenshot 2024-01-21 at 11.06.03 PM.png

© 2024    •  Powered by Soopr   •  Theme  Moonwalk