0
# CSRF Protection
1
2
Cross-Site Request Forgery (CSRF) protection for Flask applications with automatic token generation, validation, and request processing. Flask-WTF provides both global application-level protection and manual token handling for custom scenarios.
3
4
## Capabilities
5
6
### CSRFProtect Class
7
8
Main CSRF protection extension that integrates with Flask's request processing cycle. Provides automatic protection for specified HTTP methods and allows exemption of specific views or blueprints.
9
10
```python { .api }
11
class CSRFProtect:
12
def __init__(self, app: Flask = None):
13
"""
14
Initialize CSRF protection.
15
16
Args:
17
app: Flask application instance (optional for factory pattern)
18
"""
19
20
def init_app(self, app: Flask):
21
"""
22
Initialize CSRF protection with Flask app (factory pattern).
23
24
Args:
25
app: Flask application instance
26
"""
27
28
def exempt(self, view):
29
"""
30
Mark a view function or blueprint exempt from CSRF protection.
31
32
Args:
33
view: View function, blueprint, or string view name
34
35
Returns:
36
The view function or blueprint (for use as decorator)
37
"""
38
39
def protect(self):
40
"""
41
Manually protect the current request with CSRF validation.
42
Raises CSRFError if validation fails.
43
"""
44
```
45
46
### Token Generation
47
48
Generate CSRF tokens for use in templates and views. Tokens are cached per request and stored in the session for validation.
49
50
```python { .api }
51
def generate_csrf(secret_key: str = None, token_key: str = None) -> str:
52
"""
53
Generate a CSRF token for the current request.
54
55
Args:
56
secret_key: Secret key for signing (defaults to WTF_CSRF_SECRET_KEY or app.secret_key)
57
token_key: Session key for token storage (defaults to WTF_CSRF_FIELD_NAME)
58
59
Returns:
60
Signed CSRF token string
61
"""
62
```
63
64
### Token Validation
65
66
Manually validate CSRF tokens in custom scenarios where automatic protection is not sufficient.
67
68
```python { .api }
69
def validate_csrf(
70
data: str,
71
secret_key: str = None,
72
time_limit: int = None,
73
token_key: str = None
74
):
75
"""
76
Validate a CSRF token against the session token.
77
78
Args:
79
data: The signed CSRF token to validate
80
secret_key: Secret key for verification (defaults to WTF_CSRF_SECRET_KEY)
81
time_limit: Token expiration time in seconds (defaults to WTF_CSRF_TIME_LIMIT)
82
token_key: Session key for stored token (defaults to WTF_CSRF_FIELD_NAME)
83
84
Raises:
85
ValidationError: If token is missing, expired, invalid, or doesn't match
86
"""
87
```
88
89
### CSRF Error Exception
90
91
Exception raised when CSRF validation fails. Inherits from Werkzeug's BadRequest for proper HTTP error handling.
92
93
```python { .api }
94
class CSRFError(BadRequest):
95
"""
96
CSRF validation failed error.
97
98
Generates 400 Bad Request response by default.
99
Customize response by registering error handler with Flask.
100
"""
101
description: str = "CSRF validation failed."
102
```
103
104
## Usage Examples
105
106
### Basic Global Protection
107
108
```python
109
from flask import Flask
110
from flask_wtf import CSRFProtect
111
112
app = Flask(__name__)
113
app.config['SECRET_KEY'] = 'your-secret-key'
114
115
# Enable CSRF protection for all views
116
csrf = CSRFProtect(app)
117
118
# Or using factory pattern
119
csrf = CSRFProtect()
120
csrf.init_app(app)
121
```
122
123
### Exempting Views
124
125
```python
126
# Exempt a single view
127
@app.route('/api/public', methods=['POST'])
128
@csrf.exempt
129
def public_api():
130
return {'status': 'ok'}
131
132
# Exempt an entire blueprint
133
from flask import Blueprint
134
api = Blueprint('api', __name__)
135
csrf.exempt(api)
136
137
# Exempt by string name
138
csrf.exempt('main.upload_file')
139
```
140
141
### Manual Token Handling
142
143
```python
144
from flask import render_template
145
from flask_wtf.csrf import generate_csrf, validate_csrf
146
147
@app.route('/custom-form')
148
def custom_form():
149
token = generate_csrf()
150
return render_template('custom.html', csrf_token=token)
151
152
@app.route('/validate-token', methods=['POST'])
153
def validate_token():
154
token = request.form.get('csrf_token')
155
try:
156
validate_csrf(token)
157
return 'Valid token'
158
except ValidationError as e:
159
return f'Invalid token: {e}', 400
160
```
161
162
### Template Integration
163
164
CSRF tokens are automatically available in Jinja2 templates:
165
166
```html
167
<!-- Automatic token function -->
168
<form method="POST">
169
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
170
<!-- form fields -->
171
</form>
172
173
<!-- Via context processor -->
174
<form method="POST">
175
<input type="hidden" name="csrf_token" value="{{ csrf_token }}"/>
176
<!-- form fields -->
177
</form>
178
```
179
180
## Configuration
181
182
### Required Configuration
183
184
```python
185
app.config['SECRET_KEY'] = 'your-secret-key-here'
186
```
187
188
### Optional CSRF Configuration
189
190
```python
191
# CSRF protection settings
192
app.config['WTF_CSRF_ENABLED'] = True # Enable/disable protection
193
app.config['WTF_CSRF_SECRET_KEY'] = 'csrf-specific-key' # Separate CSRF key
194
app.config['WTF_CSRF_FIELD_NAME'] = 'csrf_token' # Token field name
195
app.config['WTF_CSRF_TIME_LIMIT'] = 3600 # Token expiration (seconds)
196
197
# HTTP method protection
198
app.config['WTF_CSRF_METHODS'] = ['POST', 'PUT', 'PATCH', 'DELETE']
199
200
# Token sources (form data and headers)
201
app.config['WTF_CSRF_HEADERS'] = ['X-CSRFToken', 'X-CSRF-Token']
202
203
# Request processing settings
204
app.config['WTF_CSRF_CHECK_DEFAULT'] = True # Auto-check requests
205
app.config['WTF_CSRF_SSL_STRICT'] = True # Enforce referrer on HTTPS
206
```
207
208
## Error Handling
209
210
### Custom Error Handler
211
212
```python
213
@app.errorhandler(CSRFError)
214
def handle_csrf_error(e):
215
return render_template('csrf_error.html'), 400
216
```
217
218
### AJAX Integration
219
220
For JavaScript/AJAX requests, include CSRF token in headers:
221
222
```javascript
223
// Get token from meta tag
224
const token = document.querySelector('meta[name=csrf-token]').getAttribute('content');
225
226
// Include in AJAX requests
227
fetch('/api/endpoint', {
228
method: 'POST',
229
headers: {
230
'X-CSRFToken': token,
231
'Content-Type': 'application/json'
232
},
233
body: JSON.stringify(data)
234
});
235
```
236
237
Template meta tag:
238
239
```html
240
<meta name="csrf-token" content="{{ csrf_token() }}">
241
```