This Flask extension is based upon the DecoratorfortheHTTPAccessControl written by Armin Ronacher.
This Flask extension is based upon the DecoratorfortheHTTPAccessControl written by Armin Ronacher.
Configuration
Flask-CORS can be configured at four different locations. Configuration values are determined in the
following order:
1. Resource level settings (e.g when passed as a dictionary)
2. Keyword argument settings
3. App level configuration settings (e.g. CORS_*)
4. Defaultsettings
See below for more information.
Configurationoptions
Configuration options are consistently named across the various locations where they can be set. A
configuration option called example can be set with the resource dictionary key example, as the keyword
argument example or as the Flask app configuration key CORS_EXAMPLE.
The configuration options recognised by Flask-CORS are:
CORS_ALLOW_HEADERS(Listorstr)
Headers to accept from the client. Headers in the Access-Control-Request-Headers request header
(usually part of the preflight OPTIONS request) matching headers in this list will be included in
the Access-Control-Allow-Headers response header.
CORS_ALLOW_PRIVATE_NETWORK(bool)
If True, the response header Access-Control-Allow-Private-Network will be set with the value
'true' whenever the request header Access-Control-Request-Private-Network has a value 'true'.
If False, the response header Access-Control-Allow-Private-Network will be set with the value
'false' whenever the request header Access-Control-Request-Private-Network has a value of 'true'.
If the request header Access-Control-Request-Private-Network is not present or has a value other
than 'true', the response header Access-Control-Allow-Private-Network will not be set.
CORS_ALWAYS_SEND(bool)
Usually, if a request doesn't include an Origin header, the client did not request CORS. This
means we can ignore this request.
However, if this is true, a most-likely-to-be-correct value is still set.
CORS_AUTOMATIC_OPTIONS(bool)
Only applies to the flask_cors.cross_origin() decorator. If True, Flask-CORS will override
Flask’s default OPTIONS handling to return CORS headers for OPTIONS requests.
CORS_EXPOSE_HEADERS(Listorstr)
The CORS spec requires the server to give explicit permissions for the client to read headers in
CORS responses (via the Access-Control-Expose-Headers header). This specifies the headers to
include in this header.
CORS_INTERCEPT_EXCEPTIONS(bool)
Whether to deal with Flask exception handlers or leave them alone (with respect to CORS headers).
CORS_MAX_AGE(timedelta,intorstr)
The maximum time for which this CORS request may be cached. This value is set as the ‐
Access-Control-Max-Age header.
CORS_METHODS(Listorstr)
The method(s) which the allowed origins are allowed to access. These are included in the ‐
Access-Control-Allow-Methods response headers to the preflight OPTIONS requests.
CORS_ORIGINS(List,strorre.Pattern)
The origin(s) to allow requests from. An origin configured here that matches the value of the ‐
Origin header in a preflight OPTIONS request is returned as the value of the ‐
Access-Control-Allow-Origin response header.
CORS_RESOURCES(Dict,Listorstr)
The series of regular expression and (optionally) associated CORS options to be applied to the
given resource path.
If the value is a dictionary, it's keys must be regular expressions matching resources, and the
values must be another dictionary of configuration options, as described in this section.
If the argument is a list, it is expected to be a list of regular expressions matching resources
for which the app-wide configured options are applied.
If the argument is a string, it is expected to be a regular expression matching resources for
which the app-wide configured options are applied.
CORS_SEND_WILDCARD(bool)
If CORS_ORIGINS is "*" and this is true, then the Access-Control-Allow-Origin response header's
value with be "*" as well, instead of the value of the Origin request header.
CORS_SUPPORTS_CREDENTIALS(bool)
Allows users to make authenticated requests. If true, injects the ‐
Access-Control-Allow-Credentials header in responses. This allows cookies and credentials to be
submitted across domains.
note This option cannot be used in conjunction with a "*" origin
CORS_VARY_HEADER:(bool)
Enables or disables the injection of the Vary response header is set to Origin. This informs
clients that our CORS headers are dynamic and cannot be cached.
Defaultvalues
• CORS_ALLOW_HEADERS: "*"
• CORS_ALLOW_PRIVATE_NETWORK: False
• CORS_ALWAYS_SEND: True
• CORS_AUTOMATIC_OPTIONS: True
• CORS_EXPOSE_HEADERS: None
• CORS_INTERCEPT_EXCEPTIONS: True
• CORS_MAX_AGE: None
• CORS_METHODS: ["GET", "HEAD", "POST", "OPTIONS", "PUT", "PATCH", "DELETE"]
• CORS_ORIGINS: "*"
• CORS_RESOURCES: r"/*"
• CORS_SEND_WILDCARD: False
• CORS_SUPPORTS_CREDENTIALS: False
• CORS_VARY_HEADER: True
LocationsResourcelevelsettings
You can specify CORS options on a resource level of granularity by passing a dictionary as the resources
keyword argument when instantiating the flask_cors.CORS object (or when calling init_app on it), mapping
paths to a set of options.
Keywordargumentsettings
For options matching all resources, it's also possible to simply set the configuration options using
keyword arguments when instantiating the flask_cors.CORS object (or when calling init_app on it).
Applevelconfigurationsettings
It's good practice to keep your application configuration settings in one place. This is also possible
with Flask-CORS using the same configuration options in the Flask application's config object.
Defaultsettings
Finally, every setting has a defaultvalue as well.
APIDocs
This package exposes a Flask extension which by default enables CORS support on all routes, for all
origins and methods. It allows parameterization of all CORS headers on a per-resource level. The package
also contains a decorator, for those who prefer this approach.
Extension
This is the suggested approach to enabling CORS. The default configuration will work well for most use
cases.
classflask_cors.CORS(app=None,**kwargs)
Initializes Cross Origin Resource sharing for the application. The arguments are identical to
cross_origin(), with the addition of a resources parameter. The resources parameter defines a
series of regular expressions for resource paths to match and optionally, the associated options
to be applied to the particular resource. These options are identical to the arguments to
cross_origin().
The settings for CORS are determined in the following order
1. Resource level settings (e.g when passed as a dictionary)
2. Keyword argument settings
3. App level configuration settings (e.g. CORS_*)
4. Default settings
Note: as it is possible for multiple regular expressions to match a resource path, the regular
expressions are first sorted by length, from longest to shortest, in order to attempt to match the
most specific regular expression. This allows the definition of a number of specific resource
options, with a wildcard fallback for all other resources.
Parameters
• resources (dict,iterableorstring) --
The series of regular expression and (optionally) associated CORS options to be applied
to the given resource path.
If the argument is a dictionary, it's keys must be regular expressions, and the values
must be a dictionary of kwargs, identical to the kwargs of this function.
If the argument is a list, it is expected to be a list of regular expressions, for which
the app-wide configured options are applied.
If the argument is a string, it is expected to be a regular expression for which the
app-wide configured options are applied.
Default : Match all and apply app-level configuration
• origins (list,stringorregex) --
The origin, or list of origins to allow requests from. The origin(s) may be regular
expressions, case-sensitive strings, or else an asterisk.
NOTE:
origins must include the schema and the port (if not port 80), e.g., CORS(app,origins=["http://localhost:8000","https://example.com"]).
Default : '*'
• methods (listorstring) --
The method or list of methods which the allowed origins are allowed to access for
non-simple requests.
Default : [GET, HEAD, POST, OPTIONS, PUT, PATCH, DELETE]
• expose_headers (listorstring) --
The header or list which are safe to expose to the API of a CORS API specification.
Default : None
• allow_headers (list,stringorregex) --
The header or list of header field names which can be used when this resource is accessed
by allowed origins. The header(s) may be regular expressions, case-sensitive strings, or
else an asterisk.
Default : '*', allow all headers
• supports_credentials (bool) --
Allows users to make authenticated requests. If true, injects the
Access-Control-Allow-Credentials header in responses. This allows cookies and credentials
to be submitted across domains.
note This option cannot be used in conjunction with a '*' origin
Default : False
• max_age (timedelta,integer,stringorNone) --
The maximum time for which this CORS request maybe cached. This value is set as the
Access-Control-Max-Age header.
Default : None
• send_wildcard (bool) --
If True, and the origins parameter is *, a wildcard Access-Control-Allow-Origin header is
sent, rather than the request's Origin header.
Default : False
• vary_header (bool) --
If True, the header Vary: Origin will be returned as per the W3 implementation
guidelines.
Setting this header when the Access-Control-Allow-Origin is dynamically generated (e.g.
when there is more than one allowed origin, and an Origin than '*' is returned) informs
CDNs and other caches that the CORS headers are dynamic, and cannot be cached.
If False, the Vary header will never be injected or altered.
Default : True
• allow_private_network (bool) --
If True, the response header Access-Control-Allow-Private-Network will be set with the
value 'true' whenever the request header Access-Control-Request-Private-Network has a
value 'true'.
If False, the response header Access-Control-Allow-Private-Network will be set with the
value 'false' whenever the request header Access-Control-Request-Private-Network has a
value of 'true'.
If the request header Access-Control-Request-Private-Network is not present or has a
value other than 'true', the response header Access-Control-Allow-Private-Network will
not be set.
Default : True
Decorator
If the CORS extension does not satisfy your needs, you may find the decorator useful. It shares options
with the extension, and should be simple to use.
flask_cors.cross_origin(*args,**kwargs)
This function is the decorator which is used to wrap a Flask route with. In the simplest case,
simply use the default parameters to allow all origins in what is the most permissive
configuration. If this method modifies state or performs authentication which may be brute-forced,
you should add some degree of protection, such as Cross Site Request Forgery protection.
Parameters
• origins (list,stringorregex) --
The origin, or list of origins to allow requests from. The origin(s) may be regular
expressions, case-sensitive strings, or else an asterisk
Default : '*'
• methods (listorstring) --
The method or list of methods which the allowed origins are allowed to access for
non-simple requests.
Default : [GET, HEAD, POST, OPTIONS, PUT, PATCH, DELETE]
• expose_headers (listorstring) --
The header or list which are safe to expose to the API of a CORS API specification.
Default : None
• allow_headers (list,stringorregex) --
The header or list of header field names which can be used when this resource is accessed
by allowed origins. The header(s) may be regular expressions, case-sensitive strings, or
else an asterisk.
Default : '*', allow all headers
• supports_credentials (bool) --
Allows users to make authenticated requests. If true, injects the
Access-Control-Allow-Credentials header in responses. This allows cookies and credentials
to be submitted across domains.
note This option cannot be used in conjunction with a '*' origin
Default : False
• max_age (timedelta,integer,stringorNone) --
The maximum time for which this CORS request maybe cached. This value is set as the
Access-Control-Max-Age header.
Default : None
• send_wildcard (bool) --
If True, and the origins parameter is *, a wildcard Access-Control-Allow-Origin header is
sent, rather than the request's Origin header.
Default : False
• vary_header (bool) --
If True, the header Vary: Origin will be returned as per the W3 implementation
guidelines.
Setting this header when the Access-Control-Allow-Origin is dynamically generated (e.g.
when there is more than one allowed origin, and an Origin than '*' is returned) informs
CDNs and other caches that the CORS headers are dynamic, and cannot be cached.
If False, the Vary header will never be injected or altered.
Default : True
• automatic_options (bool) --
Only applies to the cross_origin decorator. If True, Flask-CORS will override Flask's
default OPTIONS handling to return CORS headers for OPTIONS requests.
Default : True
UsingCORSwithcookies
By default, Flask-CORS does not allow cookies to be submitted across sites, since it has potential
security implications. If you wish to enable cross-site cookies, you may wish to add some sort of CSRF
protection to keep you and your users safe.
To allow cookies or authenticated requests to be made cross origins, simply set the supports_credentials
option to True. E.g.
from flask import Flask, session
from flask_cors import CORS
app = Flask(__name__)
CORS(app, supports_credentials=True)
@app.route("/")
def helloWorld():
return "Hello, %s" % session['username']
The above code enables Flask backend to accept cookies to be submitted from cross origin sites. But if
you are sending Xhr requests (ajax calls) to a cross-origin server, by default chrome or any modern
browser won't send cookies and session with the request. You should use withCredentials=True while
sending Xhr request to enable that. You should keep in mind about the necessary security concerns.
Related MDN doc: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentialsUsingCORSwithBlueprints
Flask-CORS supports blueprints out of the box. Simply pass a blueprint instance to the CORS extension,
and everything will just work.
api_v1 = Blueprint('API_v1', __name__)
CORS(api_v1) # enable CORS on the API_v1 blue print
@api_v1.route("/api/v1/users/")
def list_users():
'''
Since the path matches the regular expression r'/api/*', this resource
automatically has CORS headers set. The expected result is as follows:
$ curl --include -X GET http://127.0.0.1:5000/api/v1/users/ \
--header Origin:www.examplesite.com
HTTP/1.0 200 OK
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Origin: *
Content-Length: 21
Content-Type: application/json
Date: Sat, 09 Aug 2014 00:26:41 GMT
Server: Werkzeug/0.9.4 Python/2.7.8
{
"success": true
}
'''
return jsonify(user="joe")
@api_v1.route("/api/v1/users/create", methods=['POST'])
def create_user():
'''
Since the path matches the regular expression r'/api/*', this resource
automatically has CORS headers set.
Browsers will first make a preflight request to verify that the resource
allows cross-origin POSTs with a JSON Content-Type, which can be simulated
as:
$ curl --include -X OPTIONS http://127.0.0.1:5000/api/v1/users/create \
--header Access-Control-Request-Method:POST \
--header Access-Control-Request-Headers:Content-Type \
--header Origin:www.examplesite.com
>> HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Allow: POST, OPTIONS
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT
Content-Length: 0
Server: Werkzeug/0.9.6 Python/2.7.9
Date: Sat, 31 Jan 2015 22:25:22 GMT
$ curl --include -X POST http://127.0.0.1:5000/api/v1/users/create \
--header Content-Type:application/json \
--header Origin:www.examplesite.com
>> HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 21
Access-Control-Allow-Origin: *
Server: Werkzeug/0.9.6 Python/2.7.9
Date: Sat, 31 Jan 2015 22:25:04 GMT
{
"success": true
}
'''
return jsonify(success=True)
public_routes = Blueprint('public', __name__)
@public_routes.route("/")
def helloWorld():
'''
Since the path '/' does not match the regular expression r'/api/*',
this route does not have CORS headers set.
'''
return '''<h1>Hello CORS!</h1> Read about my spec at the
<a href="http://www.w3.org/TR/cors/">W3</a> Or, checkout my documentation
on <a href="https://github.com/corydolphin/flask-cors">Github</a>'''
logging.basicConfig(level=logging.INFO)
app = Flask('FlaskCorsBlueprintBasedExample')
app.register_blueprint(api_v1)
app.register_blueprint(public_routes)
if __name__ == "__main__":
app.run(debug=True)
ExamplesUsingtheCORSextension
# One of the simplest configurations. Exposes all resources matching /api/* to
# CORS and allows the Content-Type header, which is necessary to POST JSON
# cross origin.
CORS(app, resources=r'/api/*')
@app.route("/")
def helloWorld():
"""
Since the path '/' does not match the regular expression r'/api/*',
this route does not have CORS headers set.
"""
return '''
<html>
<h1>Hello CORS!</h1>
<h3> End to end editable example with jquery! </h3>
<a class="jsbin-embed" href="http://jsbin.com/zazitas/embed?js,console">JS Bin on jsbin.com</a>
<script src="//static.jsbin.com/js/embed.min.js?3.35.12"></script>
</html>
'''
@app.route("/api/v1/users/")
def list_users():
"""
Since the path matches the regular expression r'/api/*', this resource
automatically has CORS headers set. The expected result is as follows:
$ curl --include -X GET http://127.0.0.1:5000/api/v1/users/ \
--header Origin:www.examplesite.com
HTTP/1.0 200 OK
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Origin: *
Content-Length: 21
Content-Type: application/json
Date: Sat, 09 Aug 2014 00:26:41 GMT
Server: Werkzeug/0.9.4 Python/2.7.8
{
"success": true
}
"""
return jsonify(user="joe")
@app.route("/api/v1/users/create", methods=['POST'])
def create_user():
"""
Since the path matches the regular expression r'/api/*', this resource
automatically has CORS headers set.
Browsers will first make a preflight request to verify that the resource
allows cross-origin POSTs with a JSON Content-Type, which can be simulated
as:
$ curl --include -X OPTIONS http://127.0.0.1:5000/api/v1/users/create \
--header Access-Control-Request-Method:POST \
--header Access-Control-Request-Headers:Content-Type \
--header Origin:www.examplesite.com
>> HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Allow: POST, OPTIONS
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT
Content-Length: 0
Server: Werkzeug/0.9.6 Python/2.7.9
Date: Sat, 31 Jan 2015 22:25:22 GMT
$ curl --include -X POST http://127.0.0.1:5000/api/v1/users/create \
--header Content-Type:application/json \
--header Origin:www.examplesite.com
>> HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 21
Access-Control-Allow-Origin: *
Server: Werkzeug/0.9.6 Python/2.7.9
Date: Sat, 31 Jan 2015 22:25:04 GMT
{
"success": true
}
"""
return jsonify(success=True)
@app.route("/api/exception")
def get_exception():
"""
Since the path matches the regular expression r'/api/*', this resource
automatically has CORS headers set.
Browsers will first make a preflight request to verify that the resource
allows cross-origin POSTs with a JSON Content-Type, which can be simulated
as:
$ curl --include -X OPTIONS http://127.0.0.1:5000/api/exception \
--header Access-Control-Request-Method:POST \
--header Access-Control-Request-Headers:Content-Type \
--header Origin:www.examplesite.com
>> HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Allow: POST, OPTIONS
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT
Content-Length: 0
Server: Werkzeug/0.9.6 Python/2.7.9
Date: Sat, 31 Jan 2015 22:25:22 GMT
"""
raise Exception("example")
@app.errorhandler(500)
def server_error(e):
logging.exception('An error occurred during a request. %s', e)
return "An internal error occurred", 500
if __name__ == "__main__":
app.run(debug=True)
Usingthecross_origindecorator
@app.route("/", methods=['GET'])
@cross_origin()
def helloWorld():
'''
This view has CORS enabled for all domains, representing the simplest
configuration of view-based decoration. The expected result is as
follows:
$ curl --include -X GET http://127.0.0.1:5000/ \
--header Origin:www.examplesite.com
>> HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 184
Access-Control-Allow-Origin: *
Server: Werkzeug/0.9.6 Python/2.7.9
Date: Sat, 31 Jan 2015 22:29:56 GMT
<h1>Hello CORS!</h1> Read about my spec at the
<a href="http://www.w3.org/TR/cors/">W3</a> Or, checkout my documentation
on <a href="https://github.com/corydolphin/flask-cors">Github</a>
'''
return '''<h1>Hello CORS!</h1> Read about my spec at the
<a href="http://www.w3.org/TR/cors/">W3</a> Or, checkout my documentation
on <a href="https://github.com/corydolphin/flask-cors">Github</a>'''
@app.route("/api/v1/users/create", methods=['GET', 'POST'])
@cross_origin(allow_headers=['Content-Type'])
def cross_origin_json_post():
'''
This view has CORS enabled for all domains, and allows browsers
to send the Content-Type header, allowing cross domain AJAX POST
requests.
Browsers will first make a preflight request to verify that the resource
allows cross-origin POSTs with a JSON Content-Type, which can be simulated
as:
$ curl --include -X OPTIONS http://127.0.0.1:5000/api/v1/users/create \
--header Access-Control-Request-Method:POST \
--header Access-Control-Request-Headers:Content-Type \
--header Origin:www.examplesite.com
>> HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Allow: POST, OPTIONS
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT
Content-Length: 0
Server: Werkzeug/0.9.6 Python/2.7.9
Date: Sat, 31 Jan 2015 22:25:22 GMT
$ curl --include -X POST http://127.0.0.1:5000/api/v1/users/create \
--header Content-Type:application/json \
--header Origin:www.examplesite.com
>> HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 21
Access-Control-Allow-Origin: *
Server: Werkzeug/0.9.6 Python/2.7.9
Date: Sat, 31 Jan 2015 22:25:04 GMT
{
"success": true
}
'''
return jsonify(success=True)
if __name__ == "__main__":
app.run(debug=True)