Search code examples
pythonpython-3.xsecurityflaskflask-restful

Check the Integrity of Message to an API Response message using JWT-extended in Flask


Assuming that I have an API endpoint api.example.com/v1/data and a GET method with @jwt-required similar to this:

from flask_jwt_extended import jwt_required
from flask_restful import Resource

class Data(Resource):
    @jwt_required
    def get(self):
        """
        GET Response message.
        """
        return {"message":"important-info", "ts":datetime}, 200

So to GET this message you need to authenticate yourself with a Bearer "access_token" in the request's header.

How could I create an HMAC for this message. Ideally I would like to add the access token, so to check the integrity of the whole message.

So I would like to have an extra field in the returned JSON called checksum with a value hash(whole_message).


Solution

  • You can use Flask's after_request to register a function that processes the response after it was generated by the view.

    For example, to do exactly what you ask for (I am using built-in python's hash function, you can import/write your own as needed):

    @app.after_request
    def after_request(response):
        data = json.loads(response.get_data())
        data['checksum'] = hash(response.get_data())
        response.set_data(json.dumps(data))
        return response
    

    However, you will have to make sure to always return a dictionary for this to work. Here are a couple alternatives:

    1) Include the view's response inside another json, e.g.:

    @app.after_request
    def after_request(response):
        data = json.loads(response.get_data())
        data = {
            'response': data,
            'checksum': hash(response.get_data())
        }
        response.set_data(json.dumps(data))
        return response
    

    2) Add the checksum to the response headers (I would go with this one). E.g.:

    @app.after_request
    def after_request(response):
        response.headers['Checksum'] = hash(response.get_data())
        return response
    

    As a final note, if you want to hash the response using the access token, as you state in your question, you can access this token from the request object, like so:

    from flask import request
    access_token = request.headers.get('Authorization')
    

    So now you can use access_token in whatever way you need.