41

I'm wondering what the main function of authorization and the handshake in Socket.IO is. I've already read their wiki and authorizing guide on GitHub but I still don't understand the following:

  1. How does the authorization work in Socket.io?
  2. What is the handshake in Socket.IO?
  3. Can I add anything to the handshakeData object?

I hope you can answer my question. Thanks.

hexacyanide
  • 88,222
  • 31
  • 159
  • 162
Joenel de Asis
  • 1,401
  • 3
  • 15
  • 14

6 Answers6

75

Edit: In Socket.IO 1.0, middleware is now used. Authorization can be done like so:

io.use(function(socket, next) {
  var handshake = socket.request;
  next();
});

If you were to need to reject the socket, just pass an error object to the next() callback. The same thing can be done with namespaces:

io.of('/namespace').use(function(socket, next) {
  var handshake = socket.request;
  next();
});

Authorization in Socket.IO is run through a function which is decided in a boolean that is passed by a callback. This function runs every time a connection attempts a handshake, and this is what it looks like:

io.set('authorization', function (handshake, callback) {
  callback(null, true);
});

The function callback() accepts two parameters. The first is the error reason, if any, and the second parameter is the boolean that decides if a client may connect or not. By default there is no authorization, so the scenario is shown in the code sample above, where the socket that is connecting is allowed passage with true.

The handshake in Socket.IO is like any other information technology related handshake. It is the process of negotiation, which in Socket.IO's case, decides whether a client may connect, and if not, denies the connection. The handshake is initiated with either a XHR or JSONP request, and doesn't do much when no authorization is specified, but can be helpful in the data passed in the handshake data object.

To answer your last question, yes, you may add anything into the handshake object. The object is the same variable reference to the socket.handshake object, which allows you to do things like this:

io.set('authorization', function (handshake, callback) {
  handshake.foo = 'bar';
  callback(null, true);
});

io.sockets.on('connection', function(socket) {
  console.log(socket.handshake.foo); // bar
});

This is very useful, because you can store socket-based properties. A common use for this is with the Express framework, where one can identify the session ID based on the cookies passed by Socket.IO, which then a matching session can be identified.

hexacyanide
  • 88,222
  • 31
  • 159
  • 162
  • 4
    This deserves more likes. The plain fact that the handshake is available via socket.handshake inside socket events is so damned useful. – Deminetix Mar 16 '14 at 00:58
  • 3
    If I call `next(new Error('Forbidden'));` – how can I get info about my connection was refused in client? I cannot .emit() from middleware because `next(new Error(''))` denies further communication. – cadavre Sep 11 '15 at 12:53
  • A bit late, but you could listen for an ``error`` event on the client socket, because the server sends error messages to the client if ``next(new Error("Forbidden"))`` is called. – Take-Some-Bytes Aug 21 '20 at 20:17
13

Since Socket.io 1.0 , Although there is backwards compatibility it is recommended to use "io.use()" in order to add your ad-hoc middleware, so in the Node Server side:

io.use(function(socket, next){
  var joinServerParameters = JSON.parse(socket.handshake.query.joinServerParameters);
  if (joinServerParameters.token == "xxx" ){
    next();          
  } else {
    //next(new Error('Authentication error'));                  
  }
  return;       
});

And on the client side, to add your own attribute to the handshake, it would look like this:

var joinServerParameters = { token: "xxx"   };    
var socket = io.connect('url' , {query: 'joinServerParameters=' + JSON.stringify(joinServerParameters)  });
2

Right now i'm using this simple method:

io.set('authorization', function (handshakeData, accept) {
  var domain = handshakeData.headers.referer.replace('http://','').replace('https://','').split(/[/?#]/)[0];
  if('myDomain.com'==domain)
    accept(null, true);
  else 
    return accept('Deny', false);
});
Diogo Garcia
  • 536
  • 1
  • 8
  • 20
0

IN THIS CASE

io.set('authorization', function (handshake, callback) {
    handshake.foo = 'bar';
    callback(null, true);
});

io.sockets.on('connection', function(socket) {
    console.log(socket.handshake.foo); // bar
});

socket.handshake.foo will give undefined

we need to call socket.request.foo here for proper value

somebody has misled us because io auth middleware takes 2 parameters with PROPER NAMES as following (request,callback) not (handshake, callback) PS: idk maybe prev io versions had 2nd scenario :)

io.set('authorization', function (request, callback) {
    request.foo = 'bar';
    callback(null, true);
});
kuubson
  • 155
  • 1
  • 3
0

If you're using JWT, in socket.io version 4 you can use the handshake object, to access authorization Bearer token

io.use(async (socket, next) => {
    try {
        const accessToken = socket.handshake.headers.authorization.substring(7);
        try {
            const decoded = jwt.verify(accessToken, process.env.ACCESS_TOKEN_SECRET);
            const user = await fetchUser(decoded.sub);
            socket.user = user;
            next();
        } catch (e) {
            console.log("token error:", e);
        }
    } catch (e) {
        next(new Error("Utilizador desconhecido"));
    }
});
-1

i know that it too late but i would like to add the information where i found very good article about handshake authorization using the socket.io.

socket.io authorization

Vora Ankit
  • 682
  • 5
  • 8