'"The CSRF session token is missing" when CSRF token is present in request

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

enter image description here

Successful request

enter image description here


Process

  1. Client makes initial request to API
  2. API creates a session, sets the cookie in browser and returns CSRF token in response header
  3. 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.



Solution 1:[1]

I also faced the same issue & solved. I think, there are multiple reasons to show this error. It may be an issue in my application implementation or in my server configuration.

I have followed this blog for my base application.

The issue is that I got "The CSRF session token is missing." screen when I try to login in my application in production server. This is a misunderstanding. Actually, I have already logged in the application in a different browser. Then when me or any other user try to login / register, we will get this error. But unfortunately same error reported by different users & they solved the error with different solutions.

  1. Flask-WTF: CSRF token missing
  2. Form validation fails due missing CSRF
  3. Flask WTF CSRF session token missing, secret_key not found
  4. Flask CSRF token missing
  5. https://nickjanetakis.com/blog/fix-missing-csrf-token-issues-with-flask
  6. https://github.com/miguelgrinberg/flasky/issues/1

I'm using Gunicorn & Ngnix in the VPS with system service. In the system service file, the sample content is given below. The code is copied from another tutorial.

[Unit]
Description=Gunicorn instance to serve myproject
After=network.target

[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/myproject
Environment="PATH=/home/sammy/myproject/myprojectenv/bin"
ExecStart=/home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app

[Install]
WantedBy=multi-user.target

My issue is that my application is not threaded. I have to configure Gunicorn to serve application in threaded mode. I got this hint from the last link I have shared.

So I changed my system service file like below one. The only change is --threads parameter in Gunicorn command.

[Unit]
Description=Gunicorn instance to serve myproject
After=network.target

[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/myproject
Environment="PATH=/home/sammy/myproject/myprojectenv/bin"
ExecStart=/home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --threads 12 --bind unix:myproject.sock -m 007 wsgi:app

[Install]
WantedBy=multi-user.target 

I don't know the relation between the thread and CSRF token. Also I don't know the best possible worker and thread counts. Now the issue is resolved. I believe that the thread and server session have some relation in Flask.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1