pythonflasksessionflask-session

Is there anything I need to do to make session data persistent across routes in Flask


I am working with a Flask project with React as front-end. I just completed the authentication work. When i tried to access the user_id which i stored in session as 'user_data' from another route via an 'axios' request, I wasn't able to access it as it said 'No data found in session'. I have encountered some like these before which will resolve if I add 'withCredentials: true' along my 'axios' request. I tried it too but nothing worked. So i even made a custom flask route that just gets the session and if there is no data it prints something like 'No_data'. As i expected it printed 'No_data'. Now I tried to print the session data in the login route itself right after creating it and it works there but it won't in other route. So the session is being created and stored but not shared across routes... I will also share my required code.

from flask import Flask, request, jsonify, session
from datetime import datetime, timedelta
from flask_cors import CORS
import threading
import uuid
import firebase_admin
from firebase_admin import credentials, firestore

app = Flask(__name__)


app.secret_key = "HelloWorld"
app.config["SESSION_PERMANENT"] = True
app.config["PERMANENT_SESSION_LIFETIMT"] = timedelta(days = 1)

CORS(app,supports_credentials=True, resources={r"/*": {"origins":"http://localhost:5173"}})

@app.after_request
def apply_cors_headers(response):
    response.headers["Access-Control-Allow-Origin"] = "http://localhost:5173"  # Allow your React app's origin
    response.headers["Access-Control-Allow-Credentials"] = "true"  # Allow cookies (sessions)
    response.headers["Access-Control-Allow-Headers"] = "Content-Type"  # Allow content-type headers
    response.headers["Access-Control-Allow-Methods"] = "POST, GET, OPTIONS"  # Allow specific methods
    return response


#Route for axios
@app.route('/login', methods=['POST'])
def login():
    data = request.get_json()
    usermail = data.get("usermail")
    password = data.get("password")

    email_query = user_collection.where("usermail", "==", usermail).stream()
    user_doc = next(email_query, None)

    if user_doc is None:
        return jsonify({"message": "User not registered"}), 404

    user_data = user_doc.to_dict()

    if user_data.get("password") != password:
        return jsonify({"message": "Invalid credentials"}), 401

    telegram_id = user_data.get("telegramID", "")
    first_login = telegram_id.strip() == ""

    # Store user data in session
    session.permanent = True
    session["user_data"] = user_data
    session.modified = True
    print(session["user_data"]) #This prints the session as it is

    return jsonify({
        "message": "Login successful",
        "first_login": first_login
    }), 200

@app.route('/addTelegramID', methods=['POST'])
def add_telegram_id():

    if 'user_data' not in session: #This gets executes showing it clearly session is not accessible
        print("Error")


    data = request.get_json()
    
    user_data = session.get('user_data')
    print(user_data)


    if user_data:
        user_id = user_data["user_id"]

    if not user_data:
        print("NO data")
        return jsonify({"message": "Unauthorized"}), 401

    telegram_id = data.get("telegramID")
    if not telegram_id:
        return jsonify({"message": "Telegram ID is required"}), 400

    user_query = user_collection.where("user_id", "==", user_id).stream()
    user_doc = next(user_query, None)

    if user_doc is None:
        return jsonify({"message": "User not found"}), 404

    user_collection.document(user_doc.id).update({"telegramID": telegram_id})

    return jsonify({"message": "Telegram ID added successfully"}), 200


#Testing route
@app.route('/test')
def test():
    user_data = session.get('user_data')
    if user_data:
        return user_data
    
    else:
        return jsonify({"message":"No data"}) #Again this gets executed showing there is no data accessible


if __name__ == '__main__':
    from scheduler import start_scheduler
    threading.Thread(target=start_scheduler, args=(reminders,), daemon=True).start()
    app.run(debug=True)

Is there anything I am missing ??


Solution

  • You should familiarize yourself with the Same Site Policy. This is likely responsible for rejecting session data in the backend. You can either use a proxy in the background or use third-party cookies.

    You define a proxy in the package.json file when using "Create React App". This forwards requests to the frontend server to the backend server. Both CORS and cookie issues are thus obsolete, as they are the same site.

    "proxy": "http://localhost:5000"
    

    If you use Vite, you can configure the proxy in the vite.config.js file. A description can be found here.

    However, if you later, during deployment, do not want to run your frontend and backend behind the same proxy server, you can use third-party cookies. The following configuration is required for this.

    app.config["SESSION_COOKIE_SAMESITE"]="None"
    app.config["SESSION_COOKIE_SECURE"]=True