Python, Flask: How to set response header for all responses
Asked Answered
S

4

45

I want to set all of my http headers responses to something like this:

response.headers["X-Frame-Options"] = "SAMEORIGIN"

I checked this question, but it only changes the header for one specific controller. I want to change all of my headers maybe in "before_request" function similar to the following logic. How can I do that?

@app.before_request
def before_request():
    # response.headers["X-Frame-Options"] = "SAMEORIGIN"
Spandex answered 8/6, 2015 at 19:8 Comment(1)
Just a note that the X-Frame-Options has been obsoleted by the frame-ancestors directive. More info on frame-ancestors w3.org/TR/CSP2/#directive-frame-ancestors and an open-source lib to imlpement Flask CSP: github.com/twaldear/flask-cspAbagael
S
87

Set the header in a @app.after_request() hook, at which point you have a response object to set the header on:

@app.after_request
def apply_caching(response):
    response.headers["X-Frame-Options"] = "SAMEORIGIN"
    return response

The flask.request context is still available when this hook runs, so you can still vary the response based on the request at this time.

Samarskite answered 8/6, 2015 at 19:11 Comment(9)
just to add to this. you should use the @app.before_request to get your header token and check for its validity.. (header should be sent with the request in javascirpt) and then your after request is where you should change the response headersPeriphery
@JohnRuddell On stock, Flask does not enforce or provide token verification. Asserting that you should do this is not true at all.Parmenides
@Parmenides if you have a token that provides validation to locked down api's (JWT for example with "Bearer" token header) then the before_request is a way to check the validity of your token. Thats all I was trying to say.Periphery
@opyate: that's a rather large edit you made there. Can you please use a comment to point out additional issues in future? I'm fairly active on SO and always open to suggestions.Samarskite
@opyate: I rolled back that edit. Hacking up the after_requests_func mapping is a much more advanced topic and perhaps should be subject of a separate question and answer pair.Samarskite
@opyate: last but not least, the after_request decorator does the exact same thing your edit did without a decorator: append to the self.after_request_funcs[None] list. You don't appear to have a corner case there at all.Samarskite
@MartijnPieters fair enough. CORS broke for me unless I did it the func-y way.Below
It oughtn't, though, so I'm stumped: github.com/pallets/flask/blob/…Below
I love the simplicity of Martijn Pieters' answer, but if caused conflicting X-Frame-Options headers, with one that I suspect gunicorn or something else below Flask in the stack was setting to DENY. The browser in the case of such a conflict falls back to DENY, so I was left about where I started. Further research led to this small tweak to his answer that is now working for me: response.headers["Content-Security-Policy"] = "frame-ancestors 'self'"Adellaadelle
E
8

The @app.after_request() hook was not adequate for my use case.

My use case is as follows: I have a google cloud function, and I want to set the CORS headers for all responses. There are possibly multiple responses, as I have to validate the input and return if there are issues with it, I have to process data and possibly return early if something fails etc. So I've created a helper function as follows:

# Helper function to return a response with status code and CORS headers
def prepare_response(res_object, status_code):
    response = flask.jsonify(res_object)
    response.headers.set('Access-Control-Allow-Origin', '*')
    response.headers.set('Access-Control-Allow-Methods', 'GET, POST')
    return response, status_code

Thus, when I want to return a response (always with CORS headers), I can now call this function and I do not duplicate the response.headers setup necessary to enable CORS.

Elsworth answered 21/11, 2019 at 1:22 Comment(0)
D
1

We can set the response headers for all responses in Python Flask application gracefully using WSGI Middleware

This way of setting response headers in Flask application context using middleware is thread safe and can be used to set custom & dynamic attributes, read the request headers this is especially helpful if we are setting custom/dynamic response headers from any helper class.

file: middleware.py

import flask
from flask import request, g

class SimpleMiddleWare(object):
    """
    Simple WSGI middleware
    """

    def __init__(self, app):
        self.app = app
        self._header_name = "any_request_header"

    def __call__(self, environ, start_response):
        """
        middleware to capture request header from incoming http request
        """
        request_id_header = environ.get(self._header_name)  # reading all request headers
        environ[self._header_name] = request_id_header  

        def new_start_response(status, response_headers, exc_info=None):
            """
            set custom response headers
            """
            # set the above captured request header as response header
            response_headers.append((self._header_name, request_id_header))
            # example to access flask.g values set in any class thats part of the Flask app & then set that as response header
            values = g.get(my_response_header, {})
            if values.get('x-custom-header'):
                response_headers.append(('x-custom-header', values.get('x-custom-header')))
            return start_response(status, response_headers, exc_info)

        return self.app(environ, new_start_response)

Calling the middleware from main class

file : main.py

from flask import Flask
import asyncio
from gevent.pywsgi import WSGIServer
from middleware import SimpleMiddleWare

    app = Flask(__name__)
    app.wsgi_app = SimpleMiddleWare(app.wsgi_app)
Digiovanni answered 18/6, 2020 at 19:18 Comment(1)
What is g? in the import statement & values = g.get(my_response_header, {}). Also what is my_response_header?Colossae
P
0

Both approaches, the @app.after_request and middleware are very good options. I prefer the middleware approach as it's a common term in other web frameworks in the market.

A simplified version of the sample provided by @scr3360 is as follows:

from typing import Any
from wsgiref.types import WSGIEnvironment

from flask import Flask


class SecurityPoliciesMiddleware:
    """
    Security policies middleware.
    """

    def __init__(self, app: Flask) -> None:
        self.app = app

    def __call__(self, environ: WSGIEnvironment, start_response: Any):

        def new_start_response(status: str, response_headers: list, exc_info=None):
            """
            set any custom response headers, for example:
            """
            response_headers.append(("X-Frame-Options", "DENY"))
            response_headers.append(("X-XSS-Protection", "1; mode=block"))
            response_headers.append(("X-Content-Type-Options", "nosniff"))

            return start_response(status, response_headers, exc_info)

        return self.app(environ, new_start_response)
Provincial answered 15/5 at 8:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.