ExpressJS & Websocket & session sharing

I found this works for me. Not sure it's the best way to do this though. First, initialize your express application:

// whatever your express app is using here...
var session = require("express-session");
var sessionParser = session({
    store: session_store,
    cookie: {secure: true, maxAge: null, httpOnly: true}
});
app.use(sessionParser);

Now, explicitly call the session middleware from the WS connection. If you're using the express-session module, the middleware will parse the cookies by itself. Otherwise, you might need to send it through your cookie-parsing middleware first.

If you're using the websocket module:

ws.on("request", function(req){
    sessionParser(req.httpRequest, {}, function(){
        console.log(req.httpRequest.session);
        // do stuff with the session here
    });
});

If you're using the ws module:

ws.on("connection", function(req){
    sessionParser(req.upgradeReq, {}, function(){
        console.log(req.upgradeReq.session);
        // do stuff with the session here
    });
});

For your convenience, here is a fully working example, using express, express-session, and ws:

var app = require('express')();
var server = require("http").createServer(app);
var sessionParser = require('express-session')({
    secret:"secret",
    resave: true,
    saveUninitialized: true
});
app.use(sessionParser);

app.get("*", function(req, res, next) {
    req.session.working = "yes!";
    res.send("<script>var ws = new WebSocket('ws://localhost:3000');</script>");
});

var ws = new require("ws").Server({server: server});
ws.on("connection", function connection(req) {
    sessionParser(req.upgradeReq, {}, function(){
        console.log("New websocket connection:");
        var sess = req.upgradeReq.session;
        console.log("working = " + sess.working);
    });
});

server.listen(3000);

I was able to get this working. I think you need to specify the secret on cookieParser instead of session store.

Example from my app:

var app = express();
var RedisStore = require('connect-redis')(express);
var sessionStore = new RedisStore();
var cookieParser = express.cookieParser('some secret');

app.use(cookieParser);
app.use(express.session({store: sessionStore}));


wss.on('connection', function(rawSocket) {

  cookieParser(rawSocket.upgradeReq, null, function(err) {
    var sessionID = rawSocket.upgradeReq.signedCookies['connect.sid'];
    sessionStore.get(sessionID, function(err, sess) {
      console.log(sess);
    });
  });

});

Feb 2022 update:

verifyClient is now discouraged. New methods of doing this is described in an issue comment.

Consult the example code for session parsing and verification for a full usage example. Sample of the verification function:

server.on('upgrade', function (request, socket, head) {
  console.log('Parsing session from request...');

  sessionParser(request, {}, () => {
    if (!request.session.userId) {
      socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
      socket.destroy();
      return;
    }

    console.log('Session is parsed!');

    wss.handleUpgrade(request, socket, head, function (ws) {
      wss.emit('connection', ws, request);
    });
  });
});

Original answer:

In version 3.2.0 of ws you have to do it a bit differently.

There is a full working example of express session parsing in the ws repo, specifically using a new feature verifyClient.

A very brief usage summary:

const sessionParser = session({
  saveUninitialized: false,
  secret: '$eCuRiTy',
  resave: false
})

const server = http.createServer(app)
const wss = new WebSocket.Server({
  verifyClient: (info, done) => {
    console.log('Parsing session from request...')
    sessionParser(info.req, {}, () => {
      console.log('Session is parsed!')
      done(info.req.session.userId)
    })
  },
  server
})

wss.on('connection', (ws, req) => {
  ws.on('message', (message) => {
    console.log(`WS message ${message} from user ${req.session.userId}`)
  })
})