Session: How to get session id from cookie value?

Created on 2 Jul 2014  路  15Comments  路  Source: expressjs/session

Could you export your cookie-to-session-id translation function as well? I'm getting the session cookie over socket.io, too. To glue express sessions and sockets together I'd use an external session store. Now I need your decrypted session id from the cookie to access the session from the store.

question

Most helpful comment

Maybe this will work for you?

var expressSession = require('express-session')
var session = expressSession({ /* configuration */ })

io.sockets.on('connection', function (socket) {
  session(socket.handshake, {}, function (err) {
    if (err) { /* handle error */ }
    var session = socket.handshake.session;
    // do stuff
  })
})

All 15 comments

That will not work without internal knowledge of express-session's implementation. From the code I see that you're using module "cookie" instead of "cookie-parser" and furthermore expect a specific signature of the cookie's value. See getcookie. It shouldn't be my task to reimplement your undocumented internals!?

I'm not sure what you want. I maintain both modules and I'm telling you the "official" answer. They will soon be merged together, so unless you want to wait for an indeterminate amount of time, you can simply use cookieParser.signedCookie to parse the cookie...

Your question was:

Could you export your cookie-to-session-id translation function as well?

Ans the answer is that the literal "cookie-to-session-id translation function" is cookieParser.signedCookie:

// get the cookie somehow from the Cookie header
// your question was "cookie-to-session-id translation function"
// so i assume you got the cookie somehow
var cookie = ...;

// now you unsign it
var sessionId = cookieParser.signedCookie(cookie, secret);

I have never used socket.io myself, but I found people talking about how to parse cookies: http://stackoverflow.com/questions/11680997/socket-io-parse-connect-2-4-1-signed-session-cookie

In that stack overflow post, connect.utils.parseSignedCookie is now called cookieParser.signedCookie, so... ? Does that not work for you?

Maybe this will work for you?

var expressSession = require('express-session')
var session = expressSession({ /* configuration */ })

io.sockets.on('connection', function (socket) {
  session(socket.handshake, {}, function (err) {
    if (err) { /* handle error */ }
    var session = socket.handshake.session;
    // do stuff
  })
})

Sorry for the confusion but I locked into your code and explored your function getcookie. There I saw checking and stripping of the signum for example. From that I didn't realize that cookie-parser's signedCookie function will do the same. Just to clarify: You're saying that signedCookie decodes to the same session id usable as key into the session store as your custom function getcookie?

Thanks for your effort and the quick response time.

Just to clarify: You're saying that signedCookie decodes to the same session id usable as key into the session store as your custom function getcookie?

Yes, signedCookie does the same decoding that getcookie does, which is where it came from. It is only manually this library because I have not yet exacted it into a more generic common library.

Really in the end I don't recommend parsing the cookie yourself, because you'll have to probbaly keep changing it with major versions of this module. Using the io.sockets.on('connection', fn) approach I pasted above is the most future-proof method, really.

Really in the end I don't recommend parsing the cookie yourself, because you'll have to probbaly keep changing it with major versions of this module.

That's why I asked for an official translation function.

Using the io.sockets.on('connection', fn) approach I pasted above is the most future-proof method, really.

Unfortunately that won't work. socket.io is totally unaware of whatever express session middleware you're using. So you don't get more express session information with a socket instance than the session cookie from the handshake. You have to set socket.handshake.session or whatever yourself. So I came up with this code:

var cookie=require('cookie'), cookieParser=require('cookie-parser');
var cookies=cookieParser.signedCookies(cookie.parse(socket.handshake.headers.cookie), sessionSecret);
if(_.isUndefined(cookies[sessionCookieName])) return next(new Error('No session cookie');
socket.sessionId=cookies[sessionCookieName];

I want you to make it official to get a reliable solution in the long term.

@aheyer have you looked at ticket based authentication instead of cookies? I created a module yesterday that should serve as an example of how to do ticket based auth for socket.io with express. You should look through the example/ directory if you're interested.
Ticket based auth for websockets seems to have a quite a few advantages over trying to use cookies, but I'm new to auth for websockets and I would be interested in hearing your thoughts. Feel free to open issues there. I am planning to use some thing like this in a coming project, probably backed by redis or mongo and I'll be adding a store for one or the other in the coming week.

Alternatively, have you looked at session.socket.io?

Really in the end I don't recommend parsing the cookie yourself, because you'll have to probbaly keep changing it with major versions of this module.

That's why I asked for an official translation function.

An official translation function is still what I consider "parsing the cookie yourself". The problem is people will parse the session cookie and assume that if there is a session ID, the session must be valid. This is not always the case, especially with session expiration. To get a session's existence, it needs to go through all the mechanisms in the module.

Unfortunately that won't work. socket.io is totally unaware of whatever express session middleware you're using.

Can you explain? How would it not be aware? Did you run the code? Here is what you should be doing:

var express = require('express')
var expressSession = require('express-session')
var http = require('http')
var io = require('socket.io')

var session = expressSession({ /* configuration */ })

// middleware
app.use(session)

// routes
app.get('/', function() {})

// setup servers
var server = http.createServer(app);
var sio = io.listen(server);

// setup socket auth with sessions
sio.set('authorization', function(handshake, accept) {
  session(handshake, {}, function (err) {
    if (err) return accept(err)
    var session = socket.handshake.session;
    // check the session is valid
    accept(null, session.user != null)
  })
})

// setup socket connections to have the session on them
sio.sockets.on('connection', function (socket) {
  session(socket.handshake, {}, function (err) {
    if (err) { /* handle error */ }
    var session = socket.handshake.session;
    // do stuff
  })
})

How would this not work?

I want you to make it official to get a reliable solution in the long term.

This module is not going to "offically" support use with socket.io unless you are going to provide us with a PR and all the necessary changes and support people who have questions about it. I also highlighted above why we are not particularly going to export a function to parse the cookie yourself, either, because you'll end up needing to just reimplement the rest of this module to know if that session ID is even valid.

TL;DR actually try the code I am posting rather than dismissing it.

Also, please try out some of @JoeWagner suggestions as well.

Thanks a lot, now I got the point. You're faking a node.js/express request and pass it to your middleware instance. I couldn't explain where the socket.handshake.session was coming from so I insisted on the cookie translation. You official solution will be stable as long as socket.handshake has the structure of express' request object. Hope, that will stay for a while. Maybe you can update the docs with some hints for noobs like me? :-)

The new socket.io versions use the same middleware structure like express: sio.use(function(socket, next)). You only need an intermediate function to translate from socket.handshake to request. Then you have access to the session with socket.handshake.session in every sio.on event handler:

var expressSession=require('express-session');
var sessionHandler=expressSession({/* config */});
sio.use(function(socket, next)
{
    var req=socket.handshake;
    req.originalUrl='/'; //Whatever your cookie path is
    sessionHandler(req, {}, next);
});

I also looked into @JoeWagner suggestions. Unfortunately I was forced to use module Lockit so Passport is out of scope. And session.socket.io is essentially doing the same as my code posted in https://github.com/expressjs/session/issues/58#issuecomment-48011455:

var SessionSockets = require('session.socket.io');
var sessionSockets = new SessionSockets(io, sessionStore, cookieParser);

It needs your internal matters as well.

You official solution will be stable as long as socket.handshake has the structure of express' request object. Hope, that will stay for a while.

Technically just the Node.js core's IncomingMessage format; rather than specifically express's. The tests for this module do not even use express, which is how serious I am in making sure anyone can use it with whatever stuff they have, and not specifically express (yes, the current module name is misleading in that regard).

Maybe you can update the docs with some hints for noobs like me? :-)

I can, because it is a frequently-asked question. If you can put some code you are using that is working (mainly because I have not used socket.io), I can certainly turn that into something on the readme.

req.originalUrl='/'; //Whatever your cookie path is

That requirement will go away when 1.7.0 is released :)

var expressSession=require('express-session');
var sessionHandler=expressSession({/* config */});
sio.use(function(socket, next)
{
    var req=socket.handshake;
    req.originalUrl='/'; //Whatever your cookie path is
    sessionHandler(req, {}, next);
});

this worked, thanks :dango:

Was this page helpful?
0 / 5 - 0 ratings