Flask session not persisting, losing data on page refresh in SPA

EDIT: I’ve realized that the else statement actually isn’t even being called, but on page refresh, it sets the logged_in value to false. The print inside the else statement never prints. How is it setting to false without me doing it?

I have a Single Page React Application being served by Flask, all on the same server. I am using socket.io-client to communicate between the backend and frontend.

After logging in, the frontend loads up the user data just fine. If I refresh the page, I am logged out and sent back in to the login page. Why is the session not persisting?

The Flask session cookie exists in Chrome. The session cookie id matches the session cookie in the browser even after refreshing and being logged out, but the backend returns that the user is not logged in.

It seems like the session cookie is losing its data on refresh.

Here is a snippet of the react code:

const ENDPOINT = "http://127.0.0.3:5000";
const SocketContext = createContext(null);
const socket = io();

export function useIsLoggedIn() {
  const navigate = useNavigate();

  const [response, setResponse] = useState(data);

  useEffect(() => {
    socket.emit('join', setResponse);
  }, []);

  if (response.success) {
    console.log("routing to dashboard...");
    navigate("/app/dashboard");
  }

  return response;
}

export function useLogIn() {
  const sendMessage = (channel, message) => {
    socket.emit(channel, message);
  };

  return { sendMessage };
}

Here is a snippet of the backend python code:


@socketio.on('join')
def on_connect(data):
    try:
        if 'logged_in' in session and session['logged_in']:
            print('logged_in')
            user_content = content.get_content(user=session['username'])
            error = None
            join_room(session['company'])
            emit('sign_in', {'content': user_content, 'error': error, 'success': True}, room=session['company'])
        else:
            print('not_logged_in')
            error = 'Invalid login credentials'
            emit('sign_in', {'content': CONTENT, 'error': error, 'success': False})
    except Exception as e:
        print(traceback.format_exc())
        # print(e)

@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def catch_all(path):
    print('path', path)
    try:
        print('session logged_in', session['logged_in'])
    except Exception as e:
        print('failed not logged_in', e)
    if 'logged_in' not in session:
        print('set logged_in to False')
        session['logged_in'] = False
        session.permanent = True
    resp = make_response(render_template('index.html'))
    return resp

I have been trying to figure out for weeks why the session is resetting and logging the user out on refresh. Any help is appreciated, thank you.

6 thoughts on “Flask session not persisting, losing data on page refresh in SPA”

  1. If you need to use Flask, you should try to handle the login status with Flask libraries, in this case, flask_login.

    I’m not giving all the details here, but I believe that you need at least the following to get it working:

    On your app definition file:

    from flask import Flask
    from flask_login import LoginManager
    
    
    login_manager = LoginManager()
    
    
    def create_app():
        """App factory."""
        app = Flask(__name__, instance_relative_config=True)
    
        login_manager.init_app(app)
        with app.app_context():
    
            from my_app.views.view_users import view_users
            from my_app.views.main_view import main_view
            app.register_blueprint(view_users)
            app.register_blueprint(main_view)
    
            # Login manager config
            login_manager.login_view = 'view_users.login'
    

    Next, you will need to create the view_users.py. This file should contain the login_user from the flask_login package.

    from flask import render_template, Blueprint, redirect, url_for
    from flask_login import login_user
    
    view_users = Blueprint('view_users', __name__)
    
    
    @view_users.route('/login', methods=['GET', 'POST'])
    def login():
        """Login the user."""
    
        if password_matches(pass_db, passw):  # you need to check the provided password - you will need a form and a html for it
            login_user(user)
    
            next = url_for('main_view.landing')
            return redirect(next)
    

    Of course, you still need to define a function for @login_manager.user_loader and the User class, inherited from flask_login.UserMixin. Please check the doc for that.

    Finally, on your view/route/endpoint definition files, decorate every route definition with @login_required:

    from flask_login import login_user, login_required, logout_user, current_user
    from flask import render_template, Blueprint
    
    main_view = Blueprint('main_view', __name__)
    
    
    @main_view.route('/landing')
    @login_required
    def landing():
        """Landing page after user login."""
        data = ['my data']
        user_details = current_user  # if you need any - this will come from your user_loader function
        return render_template(
                'landing.html',
                data=data
            )
    
    
    @main_view.route('/a_end_point')
    @login_required
    def a_end_point():
        """Landing page after user login."""
        user_details = current_user  # if you need any - this will come from your user_loader function
        data = ['my data']
        return render_template(
                'a_end_point.html',
                data=data
            )
    

    Good luck!

    Reply

Leave a Comment