Skip to content

Instantly share code, notes, and snippets.

@artgillespie
Created February 28, 2015 02:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save artgillespie/1990f5d2efda4c51947d to your computer and use it in GitHub Desktop.
Save artgillespie/1990f5d2efda4c51947d to your computer and use it in GitHub Desktop.
Integrating socket.io with Express.js sessions.
/*jslint unparam:true, node:true*/
'use strict';
var express = require('express'),
session = require('express-session'),
cookie = require('cookie'),
cookieParser = require('cookie-parser');
var app = express();
/*
* This is the dance you need to serve the /socket.io endpoint
* with expressjs. Source: http://socket.io/docs/#using-with-express-3/4
*/
var http = require('http').Server(app);
var io = require('socket.io')(http);
/*
* We'll need the cookie name in our socket.io code. It's fine
* to use express-session default (`connect.sid`) but best
* to make it explicit.
*/
var SESSION_COOKIE_NAME = 'session.id';
var SESSION_COOKIE_SECRET = 's3kkr1t';
/*
* This is what we'll use to integrate our session.io code with
* express-session. Since we only use `set` and `get` on the store,
* the same approach should work with any session store—`redis-connect`,
* your own custom session storage, etc.
*/
var sessionStore = new session.MemoryStore();
/*
* Set up `express-session`
*/
app.use(session({
store: sessionStore,
name: SESSION_COOKIE_NAME,
secret: SESSION_COOKIE_SECRET,
saveUninitialized: true,
resave: true
}));
/*
* Render index.jade.
*/
app.get('/', function(req, res) {
if (req.session.count) {
req.session.count++;
} else {
req.session.count = 1;
}
res.render(app.path() + 'index.jade', {count: req.session.count});
// notify any clients interested in the session's count
io.to(req.session.id).emit('count', req.session.count);
});
/*
* In this example, we require an existing Express session and pass on errors
* if we don't find one. Obviously you can do anything you want here.
* The takeaway is:
* - Access the underlying HTTP request at `socket.request` to check for
* cookies, auth headers, whatever.
* - call `next(new Error('...'));` if you don't like what you see. The
* connection will never complete. (clients will receive an error)
* - call `next();` if everything's cool and you want the connection to proceed.
*/
io.use(function(socket, next) {
// turn the raw cookie header into an object
var cookies = cookie.parse(socket.request.headers.cookie);
// make sure we have a session id
if (!cookies[SESSION_COOKIE_NAME]) {
return next(new Error('valid session required'));
}
// note this is the *signed* cookie
var ssid = cookies[SESSION_COOKIE_NAME];
// check the signed cookie
var sid = cookieParser.signedCookie(ssid, SESSION_COOKIE_SECRET);
// `signedCookie` will return the same string it was passed if it fails
// so if our signed and 'un-signed' cookie are the same value, something's wrong
if (ssid === sid) {
// not a signed cookie
return next(new Error('valid session required'));
}
// now use the session store we set up earlier to find the session object
// associated with `sid`
sessionStore.get(sid, function(err, sess) {
if (err || !sess) {
return next(new Error('valid session required'));
}
// just store the session id on the socket, not the session object itself
// why? because the session would quickly become stale... you want to
// `sessionStore.get(...)` the session using the sessionId every time you
// use it. (and `sessionStore.set(...)` it every time you mutate it.
socket.sessionId = sid;
// ... and hand off
return next();
});
});
io.on('connection', function(socket) {
// have the client join its session's 'room'
socket.join(socket.sessionId, function(err) {
// whenever we receive an `incr` message, fetch the socket's session,
// fetch the session, increment `count`, and save the session.
socket.on('incr', function(msg) {
// get the session
sessionStore.get(socket.sessionId, function(err, sess) {
if (err || !sess) {
// error-handling is for chumps!
return;
}
// increment the count
if (sess.count) {
sess.count++;
} else {
sess.count = 1;
}
// IMPORTANT! save the session. this happens automatically in express handlers, but
// not here
sessionStore.set(socket.sessionId, sess, function(){});
// notify anyone that's interested in the session
io.to(socket.sessionId).emit('count', sess.count);
});
});
});
});
var server = http.listen(3000, function() {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});
doctype html
html(lang='en')
head
title= SocketSession
script(src='https://code.jquery.com/jquery-2.1.3.min.js')
script(src='/socket.io/socket.io.js')
script(type='text/javascript').
$(function() {
var socket = io();
socket.on('count', function(msg) {
$('#count').text(msg);
});
$('#increment-btn').click(function(e) {
socket.emit('incr', {});
});
});
body
h1 Hello, SocketSession
h4(id='count') #{count}
button(id='increment-btn') Increment
@artgillespie
Copy link
Author

Integrating Express.js Sessions with Socket.io

I had what I thought was a simple requirement: Integrate an express app's sessions with socket.io connections. I found very little current (socket.io 1.0 + express 4.x) information via google and stack overflow, so I thought I'd break out the results of several hours of trial and error and share them here. I'm relatively new to node.js, express, and socket.io—any feedback on violated idioms, bugs, etc. gratefully received.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment