Access-Control-Allow-Origin: * allows any website to access your resources. Always specify exact origins in production.
The recommended approach is to use the Flask-CORS Python package, which handles all CORS edge cases automatically.
$ pip install -U flask-cors
Allow a single trusted origin:
# app.py
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app, origins=["https://example.com"])
@app.route("/api/data")
def get_data():
return {"message": "CORS enabled"}
if __name__ == "__main__":
app.run()
Allow multiple specific origins (issue #146):
# app.py
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
# Allow multiple specific origins
cors = CORS(app, origins=[
"https://example.com",
"https://app.example.com",
"https://admin.example.com"
])
@app.route("/api/data")
def get_data():
return {"message": "CORS enabled"}
When using cookies or authentication:
# app.py
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
# Enable credentials (cookies, authorization headers)
cors = CORS(
app,
origins=["https://example.com"],
supports_credentials=True
)
@app.route("/api/secure")
def secure_endpoint():
return {"message": "Authenticated request"}
Apply CORS to specific routes only:
# app.py
from flask import Flask
from flask_cors import CORS, cross_origin
app = Flask(__name__)
# Public endpoint with CORS
@app.route("/api/public")
@cross_origin(origins=["*"])
def public_api():
return {"message": "Public endpoint"}
# Private endpoint with restricted CORS
@app.route("/api/private")
@cross_origin(
origins=["https://example.com"],
supports_credentials=True
)
def private_api():
return {"message": "Private endpoint"}
# No CORS
@app.route("/internal")
def internal_api():
return {"message": "Internal only"}
Customize all CORS options:
# app.py
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
cors_config = {
"origins": ["https://example.com", "https://app.example.com"],
"methods": ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
"allow_headers": ["Content-Type", "Authorization", "X-Requested-With"],
"expose_headers": ["Content-Length", "X-Custom-Header"],
"supports_credentials": True,
"max_age": 86400
}
CORS(app, resources={r"/api/*": cors_config})
@app.route("/api/data")
def get_data():
return {"message": "CORS enabled with custom config"}
Validate origins programmatically:
# app.py
from flask import Flask, request
from flask_cors import CORS
app = Flask(__name__)
def check_origin(origin):
"""Custom origin validation logic"""
allowed_origins = [
"https://example.com",
"https://app.example.com"
]
return origin in allowed_origins
CORS(
app,
origins=check_origin,
supports_credentials=True
)
@app.route("/api/data")
def get_data():
return {"message": "CORS with dynamic validation"}
If you prefer not to use Flask-CORS, implement manually:
# app.py
from flask import Flask, request, make_response
app = Flask(__name__)
ALLOWED_ORIGINS = [
"https://example.com",
"https://app.example.com"
]
@app.after_request
def add_cors_headers(response):
origin = request.headers.get('Origin')
if origin in ALLOWED_ORIGINS:
response.headers['Access-Control-Allow-Origin'] = origin
response.headers['Access-Control-Allow-Credentials'] = 'true'
response.headers['Vary'] = 'Origin'
return response
@app.route("/api/data", methods=['GET', 'POST', 'OPTIONS'])
def api_data():
# Handle preflight
if request.method == 'OPTIONS':
response = make_response('', 204)
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
response.headers['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
response.headers['Access-Control-Max-Age'] = '86400'
return response
return {"message": "CORS enabled"}
Run the development server:
$ flask run # or $ python app.py
Note: The Flask-CORS package automatically handles preflight OPTIONS requests, validates origins, and includes the Vary: Origin header when needed. For full details read the Flask-CORS package documentation.
Production Tip: Never use CORS(app) without parameters in production. Always explicitly specify allowed origins to prevent security vulnerabilities.
For comprehensive testing instructions including curl commands, browser DevTools usage, and troubleshooting common CORS errors, see the CORS Testing Guide.
The content on this site stays fresh thanks to help from users like you! If you have suggestions or would like to contribute, fork us on GitHub.
Save 39% on CORS in Action with promotional code hossainco at manning.com/hossain