Get user id socket.io, passport, koa
Asked Answered
A

2

5

I'm using Koa, Passport.js and koa-session to authenticate users. So it basically looks like:

// session
var session = require('koa-session');
app.keys = [config.secret];
app.use(session());


// auth
require(__dirname+'/lib/auth'); // de/serializeUser, strategies etc..
var passport = require('koa-passport');
app.use(passport.initialize());
app.use(passport.session());

This works well. On requests I do have the req.user, with the user id. But when using sockets, I can do:

io.on('connection', function(socket) {
  console.log(socket.request.headers.cookie),
});

But of course it's only the encrypted session ID, how could I deserialize the user and get the user.id just like I do when I get the req.user on get or post request?

Thank you in advance.

Accustomed answered 30/10, 2014 at 1:5 Comment(0)
G
11

This is a very late response but I hope it will be of use to you.

The first issue you will run into is that koa-session does not use real session stores. It embeds all information in the cookie itself and then parses it to and from the client. While this can be convenient, it works against you when trying to incorporate Socket.IO, as Socket.IO has no access to koa-session.

You'll need to migrate to koa-generic-session and use a session store to keep track of your sessions. This is, in my opinion, a better move regardless. I am currently using koa-redis for my session stores.

In order to have access to your sessions in Socket.IO, you will need to set up a global store. Here's what my global store looks like.

// store.js

var RedisStore = require('koa-redis'),
    store = undefined; // global

module.exports = function(app, settings) {
    // Where (app) is Koa and (settings) is arbitrary information
    return (function(app, settings) {
        store = store || new RedisStore();
        return store;
    })(app, settings);
}

After that, the initial setup is easy.

// app.js

... arbitrary code here ...

var session = require('koa-generic-session');

app.keys = [config.secret];
app.use(session({
    store: require('./store')(app, settings)
}));

... arbitrary code here ...
    

Now that you have a global session storage, you can then access it in Socket.IO. Please keep in mind you will need to install the cookie and co modules.

// io.js

var cookie = require('cookie'),
    co = require('co'),
    store = require('./store')(null, settings); // We don't require the Koa app

io.use(function(socket, next){
    // Now you will need to set up the authorization middleware. In order to
    // authenticate, you will need the SID from the cookie generated by
    // koa-generic-session. The property name is by default 'koa.sid'.

    var sid = cookie.parse(socket.handshake.headers.cookie)['koa.sid'];

    // We need co to handle generators for us or everything will blow up
    // when you try to access data stores designed for Koa.

    co(function*(){
        // 'koa:sess:' is the default prefix for generic sessions.
        var session = yield store.get('koa:sess:' + sid);
        
        // At this point you can do any validation you'd like. If all is well,
        // authorize the connection. Feel free to add any additional properties
        // to the handshake from the session if you please.

        if (session) next(null, true) // authenticated
        else throw new Error('Authentication error.');
    });
});

io.on('connection', function(socket){
    // Access handshake here.
});

I've adjusted the code for Socket.IO v1. I hope this helps.

Genetic answered 28/12, 2014 at 7:4 Comment(1)
Looks like Firefox (v. 36) doesn't send cookies with websocket requests, so this won't work there. I'm looking into a solution currently where the web page receives a token that the sockets can then send back to the server with each request and can by those means be validated.Katushka
D
0

I used a regex to grab the userId and found then in my database. Not the cleanest approach but it works well. I'm just using koa-session-store as my session with passport js.

  var cookies = socket.request.headers.cookie;
  var regEx = /passport"\:\{"user"\:"(.+?)"\}/g
  var userIdMatches = regEx.exec(cookies);
Deicer answered 23/6, 2015 at 18:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.