Flask Snippets

Snippets are unofficial and unmaintained.

This is an archived view of user-submitted snippets. Despite being hosted on the Flask site, they are not official. No Flask maintainer has curated or checked the snippets for security, correctness, or design.

Decorator for the HTTP Access Control

Posted by Armin Ronacher on 2011-07-14 @ 12:44 and filed in Decorators

Cross-site HTTP requests are HTTP requests for resources from a different domain than the domain of the resource making the request. For instance, a resource loaded from Domain A makes a request for a resource on Domain B. The way this is implemented in modern browsers is by using HTTP Access Control headers: Documentation on developer.mozilla.org.

The following view decorator implements this:

from datetime import timedelta
from flask import make_response, request, current_app
from functools import update_wrapper

def crossdomain(origin=None, methods=None, headers=None,
                max_age=21600, attach_to_all=True,
    if methods is not None:
        methods = ', '.join(sorted(x.upper() for x in methods))
    if headers is not None and not isinstance(headers, basestring):
        headers = ', '.join(x.upper() for x in headers)
    if not isinstance(origin, basestring):
        origin = ', '.join(origin)
    if isinstance(max_age, timedelta):
        max_age = max_age.total_seconds()

    def get_methods():
        if methods is not None:
            return methods

        options_resp = current_app.make_default_options_response()
        return options_resp.headers['allow']

    def decorator(f):
        def wrapped_function(*args, **kwargs):
            if automatic_options and request.method == 'OPTIONS':
                resp = current_app.make_default_options_response()
                resp = make_response(f(*args, **kwargs))
            if not attach_to_all and request.method != 'OPTIONS':
                return resp

            h = resp.headers

            h['Access-Control-Allow-Origin'] = origin
            h['Access-Control-Allow-Methods'] = get_methods()
            h['Access-Control-Max-Age'] = str(max_age)
            if headers is not None:
                h['Access-Control-Allow-Headers'] = headers
            return resp

        f.provide_automatic_options = False
        return update_wrapper(wrapped_function, f)
    return decorator

Unmodified this decorator requires Flask 0.8. If you want to use it with earlier versions of Flask you need to make sure to explicitly enable 'OPTIONS' as method when creating the route.

Here a basic overview of what the parameters do:

And here is how you can use it:

def my_service():
    return jsonify(foo='cross domain ftw')

Please keep in mind that with Flask 0.7 you need to explicitly provide OPTIONS:

@app.route('/my_service', methods=['GET', 'OPTIONS'])
def my_service():
    return jsonify(foo='cross domain ftw')

This snippet by Armin Ronacher can be used freely for anything you like. Consider it public domain.