0
# Cross-Origin Decorator
1
2
The `cross_origin` decorator provides route-specific Cross-Origin Resource Sharing configuration for individual Flask routes. It offers fine-grained control over CORS settings on a per-route basis with automatic OPTIONS request handling.
3
4
## Capabilities
5
6
### Cross-Origin Decorator Function
7
8
Decorator function that wraps Flask route handlers to enable CORS with configurable parameters. Applied directly to route functions for granular CORS control.
9
10
```python { .api }
11
def cross_origin(
12
origins="*",
13
methods=None,
14
expose_headers=None,
15
allow_headers="*",
16
supports_credentials=False,
17
max_age=None,
18
send_wildcard=False,
19
vary_header=True,
20
automatic_options=True,
21
allow_private_network=False,
22
always_send=True,
23
**kwargs
24
):
25
"""
26
Decorator to enable CORS for specific Flask routes.
27
28
Parameters:
29
- origins: Allowed origins (string, list, or regex patterns)
30
- methods: Allowed HTTP methods (list or string)
31
- expose_headers: Headers safe to expose to CORS API (list or string)
32
- allow_headers: Headers allowed in requests (list, string, or regex)
33
- supports_credentials: Allow authenticated requests (bool)
34
- max_age: Cache time for preflight requests (timedelta, int, or string)
35
- send_wildcard: Send '*' instead of specific origin (bool)
36
- vary_header: Include Vary: Origin header (bool)
37
- automatic_options: Handle OPTIONS requests automatically (bool)
38
- allow_private_network: Allow private network access (bool, default: False)
39
- always_send: Send CORS headers even without Origin header (bool)
40
- **kwargs: Additional configuration options
41
42
Returns:
43
Decorated function with CORS headers applied
44
"""
45
```
46
47
## Usage Examples
48
49
### Basic Route Decoration
50
51
```python
52
from flask import Flask
53
from flask_cors import cross_origin
54
55
app = Flask(__name__)
56
57
@app.route("/api/data")
58
@cross_origin() # Allow all origins with default settings
59
def get_data():
60
return {"message": "CORS-enabled data"}
61
62
@app.route("/api/public")
63
@cross_origin(origins="*") # Explicit wildcard
64
def public_endpoint():
65
return {"data": "public information"}
66
```
67
68
### Specific Origins
69
70
```python
71
from flask import Flask
72
from flask_cors import cross_origin
73
74
app = Flask(__name__)
75
76
@app.route("/api/secure")
77
@cross_origin(origins=["https://trusted-site.com", "https://app.example.com"])
78
def secure_endpoint():
79
return {"data": "restricted data"}
80
81
@app.route("/api/development")
82
@cross_origin(origins=["http://localhost:3000", "http://localhost:8080"])
83
def development_endpoint():
84
return {"data": "development data"}
85
```
86
87
### Regex Origins
88
89
```python
90
import re
91
from flask import Flask
92
from flask_cors import cross_origin
93
94
app = Flask(__name__)
95
96
@app.route("/api/subdomains")
97
@cross_origin(origins=r"https://.*\.example\.com")
98
def subdomain_endpoint():
99
return {"data": "subdomain accessible"}
100
101
@app.route("/api/pattern")
102
@cross_origin(origins=[
103
re.compile(r"https://app\d+\.example\.com"),
104
"https://main.example.com"
105
])
106
def pattern_endpoint():
107
return {"data": "pattern matched"}
108
```
109
110
### Method-Specific CORS
111
112
```python
113
from flask import Flask, request
114
from flask_cors import cross_origin
115
116
app = Flask(__name__)
117
118
@app.route("/api/users", methods=["GET", "POST"])
119
@cross_origin(
120
origins=["https://frontend.example.com"],
121
methods=["GET", "POST"],
122
allow_headers=["Content-Type", "X-Requested-With"]
123
)
124
def users_endpoint():
125
if request.method == "GET":
126
return {"users": []}
127
elif request.method == "POST":
128
return {"created": True}
129
```
130
131
### Credentials Support
132
133
```python
134
from flask import Flask
135
from flask_cors import cross_origin
136
137
app = Flask(__name__)
138
139
@app.route("/api/auth/profile")
140
@cross_origin(
141
origins=["https://app.example.com"],
142
supports_credentials=True,
143
allow_headers=["Content-Type", "Authorization"]
144
)
145
def user_profile():
146
# This route accepts cookies and credentials
147
return {"profile": "user data"}
148
149
@app.route("/api/auth/login", methods=["POST"])
150
@cross_origin(
151
origins=["https://app.example.com"],
152
supports_credentials=True,
153
methods=["POST"]
154
)
155
def login():
156
return {"token": "auth-token"}
157
```
158
159
### Custom Headers Configuration
160
161
```python
162
from flask import Flask
163
from flask_cors import cross_origin
164
165
app = Flask(__name__)
166
167
@app.route("/api/upload", methods=["POST"])
168
@cross_origin(
169
origins=["https://uploader.example.com"],
170
allow_headers=["Content-Type", "X-File-Name", "X-Upload-Key"],
171
expose_headers=["X-Upload-ID", "X-Processing-Status"],
172
methods=["POST", "OPTIONS"]
173
)
174
def file_upload():
175
return {"upload_id": "12345", "status": "processing"}
176
```
177
178
### Preflight Caching
179
180
```python
181
from datetime import timedelta
182
from flask import Flask
183
from flask_cors import cross_origin
184
185
app = Flask(__name__)
186
187
@app.route("/api/heavy-operation", methods=["POST"])
188
@cross_origin(
189
origins=["https://client.example.com"],
190
max_age=timedelta(hours=1), # Cache preflight for 1 hour
191
methods=["POST"]
192
)
193
def heavy_operation():
194
# Expensive operation that benefits from preflight caching
195
return {"result": "computed"}
196
197
@app.route("/api/frequent-calls")
198
@cross_origin(
199
origins=["https://dashboard.example.com"],
200
max_age=3600, # Cache for 1 hour (seconds)
201
allow_headers=["Content-Type", "Authorization"]
202
)
203
def frequent_endpoint():
204
return {"data": "frequently accessed"}
205
```
206
207
### OPTIONS Handling Control
208
209
```python
210
from flask import Flask, jsonify
211
from flask_cors import cross_origin
212
213
app = Flask(__name__)
214
215
@app.route("/api/custom-options", methods=["GET", "POST", "OPTIONS"])
216
@cross_origin(
217
origins=["https://custom.example.com"],
218
automatic_options=False # Handle OPTIONS manually
219
)
220
def custom_options_endpoint():
221
if request.method == "OPTIONS":
222
# Custom preflight response
223
return jsonify({"preflight": "custom response"})
224
elif request.method == "GET":
225
return {"data": "get response"}
226
elif request.method == "POST":
227
return {"data": "post response"}
228
```
229
230
### Mixed Configuration
231
232
```python
233
from flask import Flask
234
from flask_cors import cross_origin
235
236
app = Flask(__name__)
237
238
@app.route("/api/complex")
239
@cross_origin(
240
origins=[
241
"https://prod.example.com", # Production
242
"https://staging.example.com", # Staging
243
r"https://.*\.dev\.example\.com", # Development subdomains
244
"http://localhost:3000" # Local development
245
],
246
methods=["GET", "POST", "PUT", "DELETE"],
247
allow_headers=[
248
"Content-Type",
249
"Authorization",
250
"X-API-Key",
251
r"X-Custom-.*" # Regex pattern for custom headers
252
],
253
expose_headers=["X-Total-Count", "X-Rate-Limit-Remaining"],
254
supports_credentials=True,
255
max_age=1800, # 30 minutes
256
vary_header=True
257
)
258
def complex_endpoint():
259
return {"data": "complex CORS configuration"}
260
```
261
262
## Integration with Flask Extensions
263
264
The cross_origin decorator works seamlessly with other Flask extensions:
265
266
### Flask-Login Integration
267
268
```python
269
from flask import Flask
270
from flask_login import login_required
271
from flask_cors import cross_origin
272
273
app = Flask(__name__)
274
275
@app.route("/api/protected")
276
@cross_origin(
277
origins=["https://app.example.com"],
278
supports_credentials=True
279
)
280
@login_required
281
def protected_endpoint():
282
return {"data": "protected resource"}
283
```
284
285
### Flask-RESTful Integration
286
287
```python
288
from flask import Flask
289
from flask_restful import Api, Resource
290
from flask_cors import cross_origin
291
292
app = Flask(__name__)
293
api = Api(app)
294
295
class UserResource(Resource):
296
@cross_origin(origins=["https://api-client.example.com"])
297
def get(self, user_id):
298
return {"user_id": user_id}
299
300
@cross_origin(
301
origins=["https://admin.example.com"],
302
methods=["POST"],
303
supports_credentials=True
304
)
305
def post(self):
306
return {"created": True}
307
308
api.add_resource(UserResource, "/api/users/<int:user_id>")
309
```
310
311
## Error Handling
312
313
The decorator provides automatic error handling for common CORS scenarios:
314
315
- **Origin Rejection**: Non-matching origins receive responses without CORS headers
316
- **Method Validation**: Unsupported methods in preflight requests are rejected
317
- **Header Validation**: Invalid headers in preflight requests are filtered
318
- **Credential Conflicts**: Automatic validation prevents wildcard origins with credentials
319
320
## Performance Considerations
321
322
- **Decorator Overhead**: Minimal performance impact per request
323
- **Options Caching**: Use `max_age` for frequently preflight-checked endpoints
324
- **Header Processing**: Only specified headers are processed and validated
325
- **Origin Matching**: Regex patterns are compiled once at decoration time