Socket.io-client: allow access to handshake headers

Created on 14 Mar 2014  ·  19Comments  ·  Source: socketio/socket.io-client

When establishing the connection, i can 'access' to query string via io.connect(url, {query:'key=value'})

I expected to be able to do something similar with the headers.

I would like to use this to build webapi, with token authentication.

Most helpful comment

+1 any updates on this?

All 19 comments

Would like to have this as well.

I think it might be better to say to 'set' the headers when making the request.

The problem with expecting header changes is that certain transports don't allow them:

  • WebSocket does not allow custom headers
  • JSONP Polling (aka <script>) don't allow them

The only condition that would allow us to set specific headers is by forcing socket.io to only use XHR Polling

I was expecting something similar to be able to authenticate the clients. Sending an authorization token (or a password) in the query string is not a good idea.

I've created a module to send credentials in the body instead: https://github.com/invisiblejs/socketio-auth

@rauchg can you explain that further, the documentation at https://github.com/Automattic/socket.io/wiki/authorizing#handshaking says:

The handshake is initiated with either an XHR request or a JSONP request

Because:

Users might want to authorize the clients based on information from the headers or IP address

Since:

Not all transports sends headers when they attempt to establish a real time connection with the server

So doesn't this indicate it can still establish a WS connection even though handshake was in XHR, and therefore using request headers for authorization is fine?

It looks like you did have code for it at one stage https://github.com/Automattic/socket.io-client/issues/344#issuecomment-9424237

So I'm guessing there were issues so it never made it to the main repo apart from cookies which looks like it has since been removed. In which case it'd be good to update the server documentation which is a bit misleading http://socket.io/docs/server-api/#namespace#use%28fn:function%29:namespace

var io = require('socket.io')();
io.use(function(socket, next){
  if (socket.request.headers.cookie) return next();
  next(new Error('Authentication error'));
});

as it indicates cookies (i.e. headers) can be used for authentication. And add a replacement to the obsolete authentication wiki document on the main site with examples for authentication and mention of problems with other approaches as I'm sure it's a common scenario.

+1 for some resolution to this. The docs and examples ate up my time as I expected better access to setting headers for token auth as well.

+1. There is an upcoming release of engine.io client which enables access to headers, which should facilitate resolving this issue.
https://github.com/socketio/engine.io-client/pull/379

Is this available from the client JS library as well? Also, did it ever actually get in? I see it is merged but I don't think it's operational, could be wrong

+1. I've run into a similar situation where I need to authenticate browser clients. socket.io-client doesn't seem to allow it.

+1 any updates on this?

Any updates on this?

Any updates on this?

Since 2.0.0, you can now provide an extraHeaders object:

const socket = io({
  transportOptions: {
    polling: {
      extraHeaders: {
        'x-clientid': 'abc'
      }
    }
  }
});

Added to the documentation here.

Since 2.0.0, you can now provide an extraHeaders object:

const socket = io({
  transportOptions: {
    polling: {
      extraHeaders: {
        'x-clientid': 'abc'
      }
    }
  }
});

Added to the documentation here.

I'm getting the following CORS error with this although I'm using cors with express:

Response to preflight request doesn't pass access control check: It does not have HTTP ok status.

@4nubhav you have to pass a handlePreflightRequest function like this:

    handlePreflightRequest: (request, response) => {
        const headers = { ... };
        response.writeHead(200, headers);
        response.end();
    }

Since 2.0.0, you can now provide an extraHeaders object:

const socket = io({
  transportOptions: {
    polling: {
      extraHeaders: {
        'x-clientid': 'abc'
      }
    }
  }
});

Added to the documentation here.

I use .of("/path") in the Socket server then what I do where I declare URL.

@4nubhav you should allow that header with handlePreflightRequest on the server-side.

const options = {
    handlePreflightRequest: (req, res) => {
        res.writeHead(200, {
            'Access-Control-Allow-Headers': 'x-clientid', // <<< this
        });
        res.end();
     },
};
const io = require('socket.io')(server, options);

Update: in Socket.IO v3, the transportOptions is not needed anymore, you can simply use:

const socket = io({
  extraHeaders: {
    'x-clientid': 'abc'
  }
});

Documentation for CORS:

Was this page helpful?
0 / 5 - 0 ratings