Extracting Session IDs from Websocket Requests in Express.js

I decided to learn websockets recently and figured that using the excellent Socket.io library along with Express. The tutorials on their website made sense, however I ran into an issue using the express-session module--cookies are not normally parsed with websocket connections, so I could not get the session data normally.

I then spent several hours reading through blog posts and Stack Overflow to figure out how to manually go through the process of parsing cookie strings and decrypting session data, which I thought I'd share here!

This assumes that you are using Express 4.x and have installed the following modules:

  • cookie - Used to parse the cookie string
  • cookie-signature - Used to decrypt the cookie
  • debug - Used to display debug messages. Replace with Winston or similar if you like.
  • express-session - Used to interface with sessions
  • session-file-store - If you're using a different data store, replace accordingly

And the resulting code looks like this:

lib/ws.js:


module.exports = function(io) {

var cookie = require("cookie");
var cookie_sign = require("cookie-signature");
var debug = require("debug")("ws");

//
// Interface with our FileStore
//
var session = require('express-session')
var FileStore = require('session-file-store')(session);

var options = {
        //
        // Live for 7 days
        //
        ttl: 3600 * 24 * 7,
        };
var store = new FileStore(options);

//
// Looking for a replacement secret?  
// Grab one from https://www.dmuth.org/diceware/
//
var secret = "keyboard cat";

io.on('connection', function(socket){

        // 
        // Parse the cookies
        // 
        var cookie_string = socket.request.headers.cookie;
        cookies = cookie.parse(cookie_string);

        // 
        // Grab the SID and remove the leading "s:"
        // 
        sid = cookies["connect.sid"];
        sid = sid.slice(2);

        // 
        // Decrypt the SID
        // 
        var sid2 = cookie_sign.unsign(sid, secret);
        debug("SID Decrypted", sid2);

        // 
        // Now fetch our session data from the file store
        // 
        store.get(sid2, function(err, session) {

                if (err) {
                        console.log("ERROR: store.get(): ", err);
                }

                socket.on("chat message", function(msg){
                   // ...
                });

                io.emit("chat message", "a user connected!");

        });

        socket.on("disconnect", function(){
                debug("User disconnected");
                io.emit("chat message", "a user disconnected!");
        });

});

} // module.exports

Then, update app.js to include Socket.IO and ws.js like this:

//
// Install socket.io
//
var socket_io = require( "socket.io" );
var io = socket_io();
app.io = io;

var lib_ws = require("./lib/ws")(io);

...and that's about it! Getting to this point was like peeling an onion--every time I made a discovery I found something new I had to deal with. So I hope you find this post in less time than it took me to figure out all that code!

5
Average: 5 (1 vote)
Your rating: None