socket.io-client how to set request header when making connection
Asked Answered
M

9

67

I'm trying to set a http header when socket.io client makes the connection request. Is there a way to do this?

Here is what i'm doing:

// server side
var io = socketio(server);

io.use(function (socket, next) {
  // authorize using authorization header in socket.request.headers
});

// client side
var socket = io();  // i'm trying to set an authorization header in this http reqeust

Any ideas? Thanks.

Mcgill answered 1/5, 2014 at 10:46 Comment(7)
When socket client makes a request, it already has request headers with it. Are you saying that you want to change those or you just want to send some tokens from socket client and based on those tokens you want to authorize the client????Trescott
I want to send a token in the header. @MOmayrMcgill
you can send that token in the query string and check it in authorization function. Should i give you an example?Trescott
@MOmayr Thanks. That's what I'm doing at the moment. But to put the token in the header is what I would like to do. Cause in that way i could reuse my auth middleware for socket.io connection request.Mcgill
Well, I think you'll have to dig socket.io for that. But you can attach an object with socket in authorization function and later use it in io.connection event.Trescott
Did you ever figure this out? Working through it too.Anent
You won't want to set any headers if your socket.io server is not on the same domain. For IE (8 at least) you cannot set headers on a cross domain ajax request. Using a query parameter and ensuring you use https is the good way to go.Harned
A
76

You can use extraHeaders option, if you are using socket.io-client >= 1.4.

For example:

var socket = io("http://localhost", {
  extraHeaders: {
    Authorization: "Bearer authorization_token_here"
  }
});

engine.io-client, which is a backend of socket.io-client, introduced extraHeaders support on 2015-11-28.

Aiglet answered 13/2, 2016 at 15:9 Comment(7)
While this appears to be a great option, it works when using the NodeJS client, but not in the browser. It states this in the read me, presumably b/c of the first link in the answer by bakavic above (not all transports allow for the setting of custom headers)Coronado
It wasn't supported on some browsers as of yesterday due to a bug, I've fixed it :)Roderickroderigo
Awesome, how do you get the headers on the server side then?Armour
Unfortunately the extraHeaders are available only with Polling mode and not with websocket...Kellam
Headers are only provided when the connection is over http(s) which is always true for the initial handshake. After that, if the client/server "upgrade" to ws(s), no headers are available. You will have to pass the auth data in the packets instead.Speculator
Use query parameters instead query: { token:'some-token-value' }Bund
On the server-side, access with socket.handshake.headers within io.on('connection', (socket) => { ... }, as docs stateInterbreed
E
19

There's a new way to do this: https://socket.io/docs/v3/middlewares/. Look under the "Sending Credentials" section.

// client
const socket = io(server, {
    transports: ['websocket', 'polling', 'flashsocket'],
    auth: {
        token: 'abc'
    }
});

// server
io.use((socket, next) => {
    const token = socket.handshake.auth.token;
    if (isValidJwt(token)){
        next();
    }else{
        next(new Error("Socket authentication error"));
    }
});

async function isValidJwt(token){
    jwt.verify(token, secrets.jwt, function(err, decoded) {
        if (err){
            console.log(err);
            return false;
        }else{
            //console.log(decoded);
            return true;
        }
    });
}
Eloiseloisa answered 21/6, 2021 at 4:5 Comment(4)
Perfect. This works very well and is the most updated answer as of today.Midway
Hands down the most efficient and scalable approach. Bravo for highlighting this.Oilla
Does not work with passport jwtTiffanytiffi
How do I populate the auth property on postman?Mongoose
L
16

It seems like the client doesn't support setting headers, as not all transports allow for the setting of headers.

This post by facundoolano details a workaround to authentication that doesn't require placing the auth token in the query string.

His workaround module can be found at https://github.com/invisiblejs/socketio-auth.

Makes me wonder why on server-side, socket.io allows for the request headers to be accessed...

Leslielesly answered 23/12, 2014 at 10:44 Comment(1)
Socket.io handshake (even for WebSockets) starts with regular REST call and further elevation to WebSocket protocol, so the answer seems wrong, on the other hand if you are using HTTP Request Headers than this should work fine...Roderickroderigo
S
4

This following information has been deprecated since socket.io 1.0

There are two methods of authorization: global or namespace (think route). The global method is set on the server with the io.set('authorization', function (handshakeData, callback) configuration call.

The handshakeData object contains the following information:

{
   headers: req.headers       // <Object> the headers of the request
 , time: (new Date) +''       // <String> date time of the connection
 , address: socket.address()  // <Object> remoteAddress and remotePort object
 , xdomain: !!headers.origin  // <Boolean> was it a cross domain request?
 , secure: socket.secure      // <Boolean> https connection
 , issued: +date              // <Number> EPOCH of when the handshake was created
 , url: request.url          // <String> the entrance path of the request
 , query: data.query          // <Object> the result of url.parse().query or a empty object
}

The above information and a deeper explanation is available on this documentation page.

Susie answered 10/12, 2014 at 1:45 Comment(2)
io.set('authorization') has actually been deprecated in 1.0: socket.io/docs/migrating-from-0-9Grapher
Guys...no need to down vote. I added edit that this is deprecated information. The answer is from 2014.Susie
R
3

As of version 2.0.0 / 2017-01-22 engine.io-client supports

[feature] Allow extraHeaders to be set for browser clients in XHR requests (#519)

However at this point the socket.io-client is not updated to support this functionality, so couple of days may make this saga end until that time use the following instructions: https://facundoolano.wordpress.com/2014/10/11/better-authentication-for-socket-io-no-query-strings/

Roderickroderigo answered 24/1, 2017 at 21:27 Comment(0)
B
2

"transportOptions" options can be used to send extra headers in socket.io request. I also explained that here :-

Node.js + Socket.io | Set custom headers on the server

Barriebarrientos answered 27/4, 2020 at 7:5 Comment(0)
G
2

For some reason, these request headers are only received if the socket server is also socket.io. If I connect to a python Websockets server for example I have no luck authenticating.

The only solution that worked for me is to use a different WebSocket client, for example, ws works fine.

import WebSocket from 'ws';

const socket = new WebSocket('wss://example.com/path', {
      headers: {
            Authorization: 'token'
         },
 });
Grandiloquent answered 22/8, 2021 at 22:54 Comment(1)
Is there any way to handle ws does not work in the browser. Browser clients must use the native WebSocket object error?Gaberdine
B
1

Short Answer: It's imposiburu based on spec... if you just need to pass info early... why not query parameters?

socket = io('localhost:5000', {
      path: '/mySocketPath',
      transports: ['websocket'],
      query: {
        token:'some-token-value'
      }
})

See @satpal-07 in https://github.com/socketio/socket.io-client/issues/1356#issuecomment-810023635

Bund answered 7/5, 2021 at 15:37 Comment(1)
Very simple: because URL length is limited which may cause very annoying issues.Oglethorpe
M
0

If you store tokens in cookies, you can just provide withCredentials: true, option.

Maui answered 22/1 at 3:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.