Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SailsJS - using sails.io.js with JWT

I have implemented an AngularJS app, communicating with Sails backend through websockets, using sails.io.js.

Since the backend is basically a pure API and will be connected to from other apps as well, I'm trying to disable sessions completely and use JWT.

I have set up express-jwt and can use regular HTTP requests quite nicely, but when I send a request through sails.io.js, nothing happens at all - websocket request keeps pending on the client, and there's nothing happening on the server (with "silly" log level).

I've tried patching sails.io.js to support the query parameter, and when connecting, I send the token from Angular, but in the best case, I get a response with error message coming from express-jwt saying credentials are missing...

I've also seen some hints that socket.js in sails needs to be modified with beforeConnect, I've seen socketio-jwt, but have no idea where and how to plug that in, in Sails.

Has anyone implemented this and is using JWT with Sails and sockets? I'd appreciate any kind of hint in what direction to go :)

like image 267
Leo Avatar asked May 07 '15 15:05

Leo


1 Answers

I realised that policy I've put in place and that was using express-jwt abstracted too much away from me, so I didn't figure out what exactly was happening. Once I looked at other examples, I've figured out that I only needed to check what's different for websocket requests than regular, and I quickly found a way around the problem.

So:

  1. set up token signing and sending on login
  2. Angular takes the token and saves to local storage
  3. Create an interceptor for HTTP requests to add authorization header and token
  4. Fix up sails.io.js to forward query parameters provided through options (as mentioned in the question)
  5. When connecting using sails.io.js, send token as query parameter, i.e. url + '?token=' + token
  6. In sails policy, check all combinations for token, including req.socket.handshake.query, as below:

    module.exports = function (req, res, next) {
    
    var token;
    
    if (req.headers && req.headers.authorization) {
    
        var parts = req.headers.authorization.split(' ');
    
        if (parts.length == 2) {
    
            var scheme = parts[0],
            credentials = parts[1];
    
            if (/^Bearer$/i.test(scheme)) {
                token = credentials;
            }
    
        } else {
            return res.json(401, {err: 'Format is Authorization: Bearer [token]'});
        }
    
    } else if (req.param('token')) {
    
        token = req.param('token');
        // We delete the token from param to not mess with blueprints
        delete req.query.token;
    
    }
    
    // If connection from socket
    else if (req.socket && req.socket.handshake && req.socket.handshake.query && req.socket.handshake.query.token) {
    
        token = req.socket.handshake.query.token;
    
    } else {
        sails.log(req.socket.handshake);
        return res.json(401, {err: 'No Authorization header was found'});
    }
    
    JWTService.verifyToken(token, function (err, token) {
    
        if (err) {
            return res.json(401, {err: 'The token is not valid'});
        }
    
        sails.log('Token valid');
    
        req.token = token;
    
        return next();
    
    });
    
    };
    

It works well! :)

like image 169
Leo Avatar answered Nov 15 '22 08:11

Leo