public
Last active

socket.io in Express 3

  • Download Gist
app.js
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
var express = require('express')
, http = require('http')
, connect = require('connect')
, io = require('socket.io');
 
var app = express();
/* NOTE: We'll need to refer to the sessionStore container later. To
* accomplish this, we'll create our own and pass it to Express
* rather than letting it create its own. */
var sessionStore = new connect.session.MemoryStore();
/* NOTE: We'll need the site secret later too, so let's factor it out.
* The security implications of this are left to the reader. */
var SITE_SECRET = 'I am not wearing any pants';
 
/*
* ... skipping some of your app settings ...
*/
app.use(express.bodyParser());
/* NOTE: Pass the cookieParser the site secret. It used to be that
* express.session() got the secret, but in Express 3 that's
* no longer the case. */
app.use(express.cookieParser(SITE_SECRET);
/* NOTE: We'll need to know the key used to store the session, so
* we explicitly define what it should be. Also, we pass in
* our sessionStore container here. */
app.use(express.session({
key: 'express.sid'
, store: sessionStore
}));
/*
* ... skipping the rest of your app settings ...
*/
 
var server = http.createServer(app);
server.listen(app.get('port'), function(){
console.log("Express server listening on port " + app.get('port'));
});
 
/**
* Socket.io
*/
var sio = io.listen(server);
 
sio.set('authorization', function(data, accept){
/* NOTE: To detect which session this socket is associated with,
* we need to parse the cookies. */
if (!data.headers.cookie) {
return accept('Session cookie required.', false);
}
 
/* XXX: Here be hacks! Both of these methods are part of Connect's
* private API, meaning there's no guarantee they won't change
* even on minor revision changes. Be careful (but still
* use this code!) */
/* NOTE: First parse the cookies into a half-formed object. */
data.cookie = require('cookie').parseCookie(data.headers.cookie);
/* NOTE: Next, verify the signature of the session cookie. */
data.cookie = require('cookie').parseSignedCookies(data.cookie, SITE_SECRET);
 
/* NOTE: save ourselves a copy of the sessionID. */
data.sessionID = data.cookie['express.sid'];
/* NOTE: get the associated session for this ID. If it doesn't exist,
* then bail. */
sessionStore.get(data.sessionID, function(err, session){
if (err) {
return accept('Error in session store.', false);
} else if (!session) {
return accept('Session not found.', false);
}
// success! we're authenticated with a known session.
data.session = session;
return accept(null, true);
});
});
 
sio.sockets.on('connection', function(socket){
var hs = socket.handshake;
console.log('A socket with sessionID '+hs.sessionID+' connected.');
 
/* NOTE: At this point, you win. You can use hs.sessionID and
* hs.session. */
 
/* NOTE: This function could end here, and everything would be fine.
* However, I included this additional mechanism that Daniel
* added to keep the session alive by pinging it every 60
* seconds. I don't know how useful this is in the context of
* this demo, considering that the sessions aren't going to
* expire in the near future. So feel free to not include this: */
var intervalID = setInterval(function(){
hs.session.reload(function(){
hs.session.touch().save();
});
}, 60 * 1000);
socket.on('disconnect', function(){
console.log('A socket with sessionID '+hs.sessionID+' disconnected.');
clearInterval(intervalID);
});
 
});

Thanks mate, this is awesome tweak!

How would you do when using socket namespaces, i.e. the

sio.of('/namespace').authorization( function(data, accept){
   //...
});

-way...?

In my case, i finally had it worked, but now it appears my server isn't listening to any socket client-event anymore... (but clients seem to get all server-side event)

Ok, my bad, I was missing the client side impacts... from now it's

var socket = io.connect('http://' + window.location.host + '/namespace');

and after that as usual:

socket.on('connect', function(){
})

instead of the old way

        var sio = io.connect();
    var socket = sio.socket;
    socket.of('/namespace')

What versions of things are you using here, i'm running the latest and I show that the cookie module does't have a parseCookie or parsedSignedCookies method. I must be missing something?

I'm having all sorts of issues with the io authorization cookie. I send that to cookie.parse and node just crashes, and on stop of that it doesn't even give me an error stack dump.

Excellent example! That is what I am looking for.

could not get this to work by copy and paste, data.headers.cookie=undefined in 'authorization'

hey bob and everyone, would you try a tiny module I wrote for the same purpose as this gist?

feedback's appreciated.

https://github.com/wcamarao/session.socket.io

why have to pass the secret to the cookieparser instead of the session?

and how can i adapt it to a login system

@wcamarao nice work, you rule.

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.