JWT Authentication and RabbitMQ for Microservices

JWT Authentication for a Secure REST API

Server-Side Implementation

import jwt
from flask import Flask, request, jsonify


app = Flask(__name__)

SECRET_KEY = 'coen4246313'

# Secured API route
@app.route('/secure-data', methods=['GET'])
def secure_data():
    token = request.headers.get('Authorization')

    if not token:
        return jsonify({"error": "Missing token"}), 401

    try:
        # Extract the token from the 'Bearer' scheme
        token = token.split(" ")[1]

        # Validate the token
        decoded_payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
        return jsonify({"message": "Access granted", "data": decoded_payload})

    except jwt.ExpiredSignatureError:
        return jsonify({"error": "Token has expired"}), 401
    except jwt.InvalidTokenError:
        return jsonify({"error": "Invalid token"}), 401

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

Client-Side Implementation

import requests
import datetime
import jwt
# Define the API endpoint
url = 'http://127.0.0.1:5000/secure-data'

# Your JWT token (replace with the actual token generated earlier)
#token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjMsInJvbGUiOiJhZG1pbiIsImV4cCI6MTcyODM1MTY1Mn0.Nh3ZyAoL7BReIGsGMcuRsH3wSZF295b__BKiMNdNCXc'

# Secret key used for signing the JWT
SECRET_KEY = 'coen4246313'

# Define the payload (data)
payload = {
    'user_id': 123,
    'role': 'admin',
    'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=1)  # Token expiration time
}

# Define the headers (algorithm)
headers = {
    'alg': 'HS256',
    'typ': 'JWT'
}

# Generate the JWT
token = jwt.encode(payload, SECRET_KEY, algorithm='HS256', headers=headers)

print(f"Generated JWT: {token}")

# Token validation
try:
    # Decode and validate the token
    decoded_payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])

    print(f"Token is valid. Decoded payload: {decoded_payload}")

except jwt.ExpiredSignatureError:
    print("Token has expired.")
except jwt.InvalidTokenError:
    print("Invalid token.")


# Define headers with the Authorization token
headers = {
    'Authorization': f'Bearer {token}'
}

# Send the GET request
response = requests.get(url, headers=headers)

# Print the response
if response.status_code == 200:
    print("Access granted:", response.json())
else:
    print(f"Access denied: {response.status_code}, {response.json()}")

Microservice Communication with RabbitMQ

Order Service (Consumer)

import pika
import json

# RabbitMQ connection and channel setup
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()

# Declare the same queue to listen for events
channel.queue_declare(queue='user_updates')

# Function to simulate updating the user’s email in the Order Service’s database
def update_email_in_order_service(user_id, new_email):
    print(f"Updating email for user {user_id} in Order Service to {new_email}")

# Callback function to process messages from RabbitMQ
def callback(ch, method, properties, body):
    event_data = json.loads(body)
    print(f"[x] Received user update event: {event_data}")
    # Update email in the Order Service’s database
    update_email_in_order_service(event_data['user_id'], event_data['new_email'])

# Setup the consumer to listen to the 'user_updates' queue
channel.basic_consume(queue='user_updates', on_message_callback=callback, auto_ack=True)

print(' [*] Waiting for messages from User Service. To exit, press CTRL+C')


channel.start_consuming()

User Service (Producer)

import pika
import json

# RabbitMQ connection and channel setup
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()

# Declare a queue named 'user_updates' for publishing events
channel.queue_declare(queue='user_updates')

# Function to simulate email update in the User Service and publish the event
def update_user_email(user_id, new_email):
    # Simulate updating the user’s email in the User Service’s database
    print(f"User {user_id} email updated to {new_email} in User Service.")

    # Create an event to notify other services about this update
    event_data = {
        "user_id": user_id,
        "new_email": new_email
    }

    # Publish the event to RabbitMQ
    message = json.dumps(event_data)
    channel.basic_publish(exchange='', routing_key='user_updates', body=message)
    print(f" [x] Published user update event: {event_data}")

# Example: Simulate a user email update
update_user_email("user_123", "newemail@example.com")

# Close the connection
connection.close()