Flask-Session and CORS - session is empty each request

125 views Asked by At

CORS does not work for me for some reason. Therefore Flask Session does not retain variables with each request to different endpoints. So, cookies not been send between frontend and backend.

Following is a snippet of my front end code. You can see I've tried to add withCredentials: true and credentials: 'include' as described in other similar issues.

import React, { useState } from "react";
import "./App.css";

  const uploadFile = async () => {
    if (!file) return;
    
    setIsLoading(true);
    try {
      const formData = new FormData();
      formData.append("file", file);
      const response = await fetch(
        `${URI}/file_upload`,
        {
          method: "POST",
          body: formData,
        },
        { credentials: 'include' }
      );
      
  } catch (error) {
     ...
    }
  }

Following is my backend code, you can see I've specified origins for CORS as a wildcard, even tried to add @cross_origin decorator - nothing helps

app = Flask(__name__)

app.secret_key = 'BAD_SECRET_KEY'
UPLOAD_FOLDER = 'uploads'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

app.config['SESSION_TYPE'] = 'filesystem'

Session(app)
CORS(app, supports_credentials=True, resources={r"*": {"origins": "*"}}, withCredentials = True)

@app.route('/file_upload', methods=['POST'])
@cross_origin(supports_credentials=True)
def upload_parse_file():
    # some code here
    ...
    print('sessions_sid', session.sid)
    session['test'] = 0
    return 'OK'

@app.route('/allin_6_9', methods=['POST'])
@cross_origin(supports_credentials=True)
def rfi():
    print('sessions_sid', session.sid)
    print('session test is', session['test'])
    return 'OK'

My react frontend runs on http://localhost:3000 Backend on http://localhost:5000

This is the error I see in browser console: Error in browser console I tried Chrome and Firefox.

This is the error I get in backend when request issued to two different endpoints.

flask run
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit
sessions_sid d440f049-1e1c-4a12-a9ce-df2285f567d9
127.0.0.1 - - [28/Nov/2023 05:55:42] "POST /file_upload HTTP/1.1" 200 -
sessions_sid ed0b9470-aaec-45fc-8fb6-6c76f7c2cd12
[2023-11-28 05:55:44,143] ERROR in app: Exception on /allin_6_9 [POST]
...
print('sessions test is', session['test'])
KeyError: 'test'

You can see that first request to /file_upload endpoint is successful! And not blocked by CORS. However second request to /allin_6_9 is blocked for some reason and does not have Access-Control-Allow-Origin header!

Therefore my Flask Session does not work. I get session sid new each time. Server error 500.

I'm stuck on this problem for a few weeks so far, trying every method out there on stackoverflow and other resources.

Versions updated to the latest: Flask Version: 3.0.0 Werkzeug Version: 3.0.1 Flask-Cors Version: 4.0.0 Flask-Session Version: 0.5.0

As per CORS documentation: "By default, Flask-CORS does not allow cookies to be submitted across sites [...] To allow cookies or authenticated requests to be made cross origins, simply set the supports_credentials option to True" - that gives no success.

Also following does not seem to help:

Adding { credentials: 'include' } to fetch in frontend and defining supports_credentials=True and origins to backend does not help.

Why does CORS works for the first request, but failes for the second one?

1

There are 1 answers

0
Vladimir Kuzmenkov On
  1. Turns out I've added credentials: 'include' incorrectly on client side. Fetch takes only 2 arguments (url and dict of arguments). The correct way would be:
const response = await fetch(
        `${URI}/file_upload`,
        {
          method: "POST",
          body: formData,
          credentials: 'include'
        },
      );

Thanks to Miguel Grinberg for pointing it out on discord.

  1. Another workaround would be to configure proxy as explained in the video https://youtu.be/N4yUiQiTvwU?si=bROQZYON2EgCBSxK