Flask-SocketIO and the User Session

The way user sessions are handled in my Flask-SocketIO extension has always been a pain point for me. I tried to make sessions work almost the same as they work on regular Flask routes, but the "almost" part is what makes it confusing for most people.

In this short article and its companion video, I will try to explain why this is not trivial, and also will go over some improvements I just released that I hope will improve the use cases on which users seem to always trip.

Default User Session Handling

The way user sessions are handled by default is by forking the Flask user session at the time the client connects to the server over Socket.IO. What does it mean to "fork" the session? It means that the contents of the Flask user session are copied over to a brand new session, specifically created for the Socket.IO connection. This session is different than the Flask session, it is actually handled by the Flask-SocketIO extension.

In practice, this handling of user sessions means that Socket.IO event handlers are going to see anything that was in the Flask user session at the time of connection. But any changes that are made to the Flask session through HTTP routes after the Socket.IO connection took place will not be accessible from Socket.IO handlers. Likewise, any changes made to the session from Socket.IO handlers will not be accessible through regular Flask routes. There are basically two user sessions, one for HTTP and one for Socket.IO.

To summarize:

  • The Flask session is copied to the Socket.IO session at the time of the Socket.IO connection.
  • Changes made to the session in Flask routes after the Socket.IO connection was made will not be accessible on the Socket.IO session.
  • Changes made to the session in Socket.IO event handlers will not be accessible on the Flask user session.

You may wonder why such a convoluted way to handle sessions. The reason lies in the fact that the server is unable to send cookies to the client through a WebSocket connection. If a Socket.IO handler makes a change to the user session, a new version of the session cookie would need to be sent to the client, and there is no standard way to do that.

Flask-Socketio's New Managed Sessions Setting

Starting with the 2.9.0 release of Flask-SocketIO, there is a new setting that controls how sessions are managed by the extension, with the optional manage_session argument given to the SocketIO class. The default value is manage_session=True, which means that Flask-SocketIO will manage its own user sessions, as described in the previous section.

Passing manage_session=False disables the extension's handling of user sessions, and instead, the Flask session handling is used. This has no practical use when working with the regular Flask user sessions based on cookies, because as explained above, cookies cannot be sent to the client on a WebSocket connection, but there are a few Flask extensions that implement server-side sessions, which for most usages, bypass the problem of having to send cookies to a client connected over WebSocket.

For example, the Flask-Session extension supports sessions with server-side storage on Redis, Memcached, MongoDB, SQLAlchemy databases or regular disk files. Updating any of these sessions is possible in a Socket.IO event handler, as long as the client already has the session id, which should be true when the session is first accessed from a regular HTTP route. As an additional limitation, the session cannot be discarded, as that will cause a new session to be created, and that will change the session id.

Using Server-Side Sessions

To use server side sessions with Flask-Session, you just need to initialize the extension and decide what storage you want to use for your sessions. The easiest configuration is to use disk files:

from flask_socketio import SocketIO
from flask_session import Session

app.config['SESSION_TYPE'] = 'filesystem'
socketio = SocketIO(app, manage_session=False)

With the above configuration, the server will create a subdirectory called flask_session in the current directory and write user sessions for all clients in it. These files will be written to by Flask or by Flask-SocketIO whenever changes to the session are made.

If you set manage_session=True instead, the user sessions will continue to be forked as described above, regardless of what type of session you use.

There is a complete example Flask-SocketIO application that uses this type of sessions in the official repository, called sessions.py. In the video above I demonstrate how this application works using all the different session modes available in the 2.9.0 release.

Flask-Login Support

I frequently receive questions regarding how to use Flask-Login with Flask-SocketIO. The good news is that the current_user context variable is fed from the user session, so that means that you can reference current_user in your Socket.IO event handlers without any problems. And if you set manage_session=False in combination with server-side sessions, you can also use login_user() and logout_user() from Socket.IO event handlers, and the changes to the user session are going to also be seen from Flask routes.

The login_required decorator is more tricky. This decorator was designed to work with Flask routes, so it cannot be used on Socket.IO event handler functions. The Flask-SocketIO documentation includes a custom decorator that has similar functionality as Flask-Login's login_required, but is designed to work with Socket.IO event handlers. For your convenience, here is the decorator source code:

import functools
from flask_login import current_user
from flask_socketio import disconnect

def authenticated_only(f):
    def wrapped(*args, **kwargs):
        if not current_user.is_authenticated:
            return f(*args, **kwargs)
    return wrapped

You can use this decorator as follows:

@socketio.on('my event')
def handle_my_custom_event(data):
    emit('my response', {'message': '{0} has joined'.format(current_user.name)},


I hope the new server-side session handling in Flask-SocketIO 2.9.0 helps alleviate the problems I see users having. If you have any suggestions to make more improvements, or you have experienced problems with user sessions not addressed with these changes, definitely let me know in the comments below, or with an issue on the GitHub repository.


  • #1 andy said 2017-08-24T19:59:53Z

    Hi, this is a very interesting post. Can this solution work with jwt? Regards

  • #2 Miguel Grinberg said 2017-08-25T21:44:18Z

    @andy: You can use JWTs for authentication, but that is unrelated to the topic of this article, which is how to share data between HTTP and Socket.IO handlers through the user session.

  • #3 christian said 2018-02-05T15:35:34Z

    Hi Miguel, many thanks for creating and maintaining flask-socketio! In a 'split-session' set up (socketio session is forked from flask (client-side) session) is it possible to use the flask-socketio testclient and access the socketio session? Something similar to the test_request_context() method of the flask testclient? Ideally I'd like to modify the socketio session during testing.

  • #4 Miguel Grinberg said 2018-02-06T03:48:45Z

    @christian: the session is maintained in a dictionary, so you could figure out how to make changes if you look at the source code. Instead, what I would recommend is that you add a new event in your test's setUp() function, and you set the session values that you need by triggering that event through the test client.

  • #5 rilwan said 2018-02-07T06:13:22Z

    I have flask web server and js on client side. Client side- socket.on('connect', function () { socket.emit('my_event', {data: 'I\'m connected!'}); }); Server side @socketio.on('connect', namespace='/test') def test_connect(): # What code here to print the emited data on server side. How to recive json at server side emited from clien. All examples are emit on both sides. On cleint side I can recieve data emited from server by below code. I want similar code in sever side(in python flask) socket.on('my_response', function (msg) { writeLog('log', 'Received #' + msg.count + ': ' + msg.data, 'warning') }); Please hlep. Much appreciated.

  • #6 Miguel Grinberg said 2018-02-08T13:50:17Z

    @rilwan: Use the following on the server: @socketio.on('my_event', data): # put your handling code here

  • #7 Rohit Thapliyal said 2018-06-29T19:32:55Z

    Hi Miguel, Thanks for this wonderful socketio Flask extension. I have an issue. I have made a chat-bot using the extension. Now, I have a function which listens at the server end (Python) and emits an appropriate response. Now, there is a case when a global variable 'flag' is changed from 0 to 1 in this function. Now, when a user is reaching this condition(changing flag to 1), the code will work for flag = 1 case. But, for every user, the value of flag is getting changed (since flag is a global variable). The different socket connections are sharing the same instance of the server-end Python script. I used sessions the way you have directed to, but still, if flag is getting changed to 1, it gets altered for other socket connections too. Here is the pseudo code: app = Flask(__name__) app.config['SESSION_TYPE'] = 'filesystem' Session(app) socketio = SocketIO(app, manage_session=False) flag = 0 @socketio.on('message') def chat(message): emit('ok', response[message]) .... if __name__ == '__main__': socketio.run(app) Please, point out where I went wrong.

  • #8 Miguel Grinberg said 2018-07-01T15:03:08Z

    @Rohit: you have to put your flag in the user session. For example: session['flag'] = 1.

  • #9 joaquin berenguer berenguer said 2018-08-31T12:26:01Z

    Miguel, My intention is to use only the your Session in the SocketIO environment, but you said you copied the previous session into a new session. In my case the previous session does not exist, any problem?

  • #10 Miguel Grinberg said 2018-08-31T12:34:50Z

    @joaquin: that is fine. If you had no previous session, then an empty session will be initialized for each Socket.IO client.

  • #11 Greg said 2018-09-17T04:02:11Z

    Thank you for this tutorial. I have 2 questions: 1- Would you recommend using flask_session, given that it's been a while that the project is inactive (the last update on Github is from couple of years ago)? Are there any alternatives that you would recommend. 2- Using flask_session, I want to use sqlalchemy configuration instead of filesystem, however I get the error that the sessions table (the default name) is not created. The documentation doesn't mention any db creation and one would assume that the table should be created automatically, could you let me know if there is any automatic way of creating the table or should I just create the table manually?

  • #12 Miguel Grinberg said 2018-09-20T22:17:19Z

    @Greg: I have used Flask-Session and never had problems with it. An alternative is Flask-KVSession, and I'm sure there are a few more on GitHub. I think the current version has a bug, it should be calling db.create_all() to trigger the creation of the table, but that line was commented out.

Leave a Comment