Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safe authentication with node.js and session.socket.io?

I'm using the latest versions of node.js and session.socket.io and this is how I set the session (please note that I'm not using a HTTPS connection so no secure: true):

app.configure(function() {
    app.use(cookieParser);
    app.use(express.session({
        signed: true,
        store: sessionStore,
        secret: 'SECRET',
        cookie: {
            maxAge: 24 * 60 * 60 * 1000,
            httpOnly: true
        }
    }));
});
var sessionSockets = new SessionSockets(io, sessionStore, cookieParser);

// Later
sessionSockets.on('connection', function(error, socket, session) {
    // session could be used here to detect if user is logged in

    // e.g. login: session.name = 'x'; session.save();
    // e.g. checkIfLoggedIn: if (session.name) return true;
});

Is my code safe/correct or how I could authenticate that a user is really logged in? Is it possible/recommended to change the sid of the cookie on the clients (due it's mentioned here)?

like image 928
David Avatar asked May 15 '13 23:05

David


2 Answers

I know this is bit old, but for future readers in addition to the approach described by @kentcdodds of parsing cookie and retrieving the session from the storage (eg. my own passport.socketio module) you might also consider a token based approach.

In this example I use JSON Web Tokens which are pretty standard. You have to give to the client page the token, in this example imagine an authentication endpoint that returns JWT:

var jwt = require('jsonwebtoken');
// other requires

app.post('/login', function (req, res) {

  // TODO: validate the actual user user
  var profile = {
    first_name: 'John',
    last_name: 'Doe',
    email: '[email protected]',
    id: 123
  };

  // we are sending the profile in the token
  var token = jwt.sign(profile, jwtSecret, { expiresInMinutes: 60*5 });

  res.json({token: token});
});

Now, your socket.io server can be configured as follows:

var socketioJwt = require('socketio-jwt');

var sio = socketIo.listen(server);

sio.set('authorization', socketioJwt.authorize({
  secret: jwtSecret,
  handshake: true
}));

sio.sockets
  .on('connection', function (socket) {
     console.log(socket.handshake.decoded_token.email, 'has joined');
     //socket.on('event');
  });

The socket.io-jwt middleware expects the token in a query string, so from the client you only have to attach it when connecting:

var socket = io.connect('', {
  query: 'token=' + token
});

I wrote a more detailed explanation about this method and cookies here.

like image 99
José F. Romaniello Avatar answered Nov 16 '22 01:11

José F. Romaniello


I would recommend avoiding re-inventing the wheel and using a library such as PassportJS. There is a module specifically for using PassportJS with Socket.io here (I've never used this though I'm currently working on a project where I'll need it soon). I have used PassportJS and it's quite simple. I would recommend this.

like image 24
kentcdodds Avatar answered Nov 16 '22 01:11

kentcdodds