Skip to content

Instantly share code, notes, and snippets.

@kbagher
Last active June 7, 2024 03:39
Show Gist options
  • Save kbagher/904e3ccf8fe6a196bdd219a12f8e5fcd to your computer and use it in GitHub Desktop.
Save kbagher/904e3ccf8fe6a196bdd219a12f8e5fcd to your computer and use it in GitHub Desktop.
This Flask code authenticates API requests using HMAC SHA256 signatures. The API headers include an apiKey and signature. The api_key_required decorator function checks the API key and signature for specified endpoints. An example POST endpoint is included.
"""
This code implements API key and signature authentication for
Flask API endpoints using HMAC SHA256 signatures.
The API headers require two parameters, `apiKey` and `signature`,
which are used to validate the request sender's identity and ensure
the integrity of the data being transmitted.
The `api_key_required` decorator function checks whether the requested
endpoint is in the `ENDPOINTS` list and performs the API key and
signature authentication check only for those endpoints.
The signature is calculated using the provided hashing key (the `SECRET_KEY`)
and the value, which is defined as the endpoint path and total parameters
(query string concatenated with the request body).
This code also includes an example POST endpoint (`/endpoint1`) that
demonstrates how to include the request body in the signature
calculation and retrieve it using Flask's `request.get_json()` method.
"""
from flask import Flask, request, jsonify
import hashlib
import hmac
import urllib.parse
app = Flask(__name__)
# Define the API key and secret key
API_KEY = "your_api_key"
SECRET_KEY = "your_secret_key"
# Define the endpoints that require API key and signature
ENDPOINTS = ['/endpoint1', '/endpoint2', '/endpoint3']
# Define the decorator function to check API key and signature
def api_key_required(func):
def wrapper(*args, **kwargs):
# Check if the API key is valid
if request.headers.get('apiKey') != API_KEY:
return jsonify({'error': 'Invalid API key'})
# Check if the signature is valid
signature = request.headers.get('signature')
if not signature:
return jsonify({'error': 'Missing signature'})
# Generate the expected signature
endpoint = request.path
total_params = urllib.parse.unquote(request.query_string.decode())
if request.method == 'POST':
total_params += request.get_data().decode()
value = endpoint + '?' + total_params if total_params else endpoint
expected_signature = hmac.new(SECRET_KEY.encode(), value.encode(), hashlib.sha256).hexdigest()
# Compare the signatures
if not hmac.compare_digest(signature, expected_signature):
return jsonify({'error': 'Invalid signature'})
# Call the original function
return func(*args, **kwargs)
return wrapper
# Define the API endpoints
@app.route('/endpoint1', methods=['POST'])
@api_key_required
def endpoint1():
data = request.get_json()
return jsonify({'message': 'Hello from endpoint1!', 'data': data})
@app.route('/endpoint2')
@api_key_required
def endpoint2():
return jsonify({'message': 'Hello from endpoint2!'})
@app.route('/endpoint3')
@api_key_required
def endpoint3():
return jsonify({'message': 'Hello from endpoint3!'})
if __name__ == '__main__':
app.run()
Flask==2.1.0
hashlib
hmac
urllib3==1.26.6
@Orch3strator
Copy link

Hello, This code snippet help a lot! Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment