I am using Flask-WTF
to use its CSRF security feature for my API. As the title suggests, the response I get from the API says that the "CSRF session token is missing". However, after inspecting the network tab in developer tools, session returned from initially accessing the API is present in the cookies section. In addition, the CSRF token is present in the request headers. Below are some images to illustrate what I mean:
Failed request
Successful request
Process
- Client makes initial request to API
- API creates a session, sets the cookie in browser and returns CSRF token in response header
- Client attaches CSRF token in every subsequent request
Example
The frontend is developed in React and the backend is developed in Python (Flask). Both are hosted Heroku. Domain registrar is with GoDaddy and I'm using Cloudflare as my DNS to re-route traffic and setting the correct domains.
A sample request looks like this:
const headers = {
'Content-Type': 'application/json',
'X-CSRF-Token': csrfToken
};
...
const handleFormSubmission = async e => {
e.preventDefault();
await axios.post('https://backend.com/add-results', { tokenId: tokenId }, { withCredentials: true, headers: headers })
}
And the backend has the following settings:
...
CORS(app, origins=["https://www.example.com"], expose_headers=["Content-Type", "X-CSRFToken"], supports_credentials=True)
...
app.config['SESSION_COOKIE_SECURE'] = True
app.config['SESSION_COOKIE_HTTPONLY'] = True
app.config['REMEMBER_COOKIE_SECURE'] = True
app.config['REMEMBER_COOKIE_HTTPONLY'] = True
app.config['SESSION_COOKIE_DOMAIN'] = 'example.com'
Note
It's very random when this error shows up. Sometimes it takes 6 requests to the API before the CSRF token is identified. In all 6 of those failed request, the CSRF token and session cookies are the same.
Not sure what's happening.