Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EXTRA HEADER with Websocket only #1356

Closed
najibghadri opened this issue Apr 21, 2020 · 15 comments
Closed

EXTRA HEADER with Websocket only #1356

najibghadri opened this issue Apr 21, 2020 · 15 comments
Labels
question Further information is requested

Comments

@najibghadri
Copy link

najibghadri commented Apr 21, 2020

Extra header is currently not supported with websocket only connection. In the documentation you said the RFC 6455 doesn't "honour it".
If you look at page 22/ 10
https://tools.ietf.org/html/rfc6455#page-22

  1. Optionally, other header fields, such as those used to send
    cookies or request authentication to a server. Unknown header
    fields are ignored, as per [RFC2616].

Clearly it supports it, and I personally find it very useful too. Also it is not that complicated with the ws library that engine.io uses.
Any support? Thanks

@AvailCat
Copy link

AvailCat commented May 14, 2020

https://github.com/socketio/engine.io-client/blob/27fa6949f38896e18a6ef426516359f8d54e7db6/lib/socket.js#L124

https://github.com/socketio/engine.io-client/blob/master/lib/transports/websocket.js#L63

By read source code mentioned above, you can make this work by:

socketIO('https://example.org', {
  path: '/api/endpoint',
  transports: ['websocket'],
  transportOptions: {
    websocket: {
      extraHeaders: {
        Cookie: 'It works',
      },
    },
  },
});

And even this:

socketIO('https://example.org', {
  path: '/api/endpoint',
  transports: ['websocket'],
  extraHeaders: {
    Cookie: 'It works',
  },
});

@najibghadri
Copy link
Author

najibghadri commented May 18, 2020

Based on the source code snippets indeed looks like there is no restriciton, but did you test it? I am going to test it later when I have time, but if it works then the documentation needs update, since:

https://socket.io/docs/client-api/#With-extraHeaders:

With extraHeaders
This only works if polling transport is enabled (which is the default). Custom headers will not be appended when using websocket as the transport. This happens because the WebSocket handshake does not honor custom headers. (For background see the WebSocket protocol RFC)

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

It states otherwise...

@behruzz
Copy link

behruzz commented May 20, 2020

Hey guys.
It did not work.
I have just tested it in my integration tests, did not work.

@AvailCat
Copy link

@najibghadri @behruzz It works for me with above example, and don't put extreHeader under polling

@MarkEhr
Copy link

MarkEhr commented Sep 7, 2020

It works for me when runninng in nodejs, it does not when running in chrome. This cannot be done as it is not supported by the browsers api https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
I need the header for my load balancer to correctly deliver the request to the socket server, but I gues we will need a different mechanism

@t-var-s
Copy link

t-var-s commented Sep 24, 2020

It seems that somebody thinks it should work, since also according to the documentation:

extraHeaders | {} | Headers that will be passed for each request to the server (via xhr-polling and via websockets). These values then can be used during handshake or for special proxies.

By the way, if you can't use cookies, does this basically mean you can only use IP addresses for sticky balancing?

@darrachequesne
Copy link
Member

@AvailCat please note that the examples you provided will not work in the browser

@rotvr if you only use the WebSocket transport, you don't need sticky session, since the WebSocket connection (and the underlying TCP connection) is kept open during the whole session.

If you do use the polling transport, the first HTTP request sets a cookie (io), which can be used for sticky-session.

More information here: https://socket.io/docs/using-multiple-nodes/

See also: socketio/engine.io-client#635 (comment)

@darrachequesne darrachequesne added the question Further information is requested label Oct 5, 2020
@satpal-07
Copy link

@darrachequesne is there a workaround to set custom headers in the browser?

@darrachequesne
Copy link
Member

@satpal-07 if you are using only websockets, there is currently no workaround (this is not covered by the WebSocket spec).

If you are using HTTP long-polling (enabled by default), this will work:

import { io } from "socket.io-client";

const socket = io({
  extraHeaders: {
    "my-custom-header": "1234"
  }
});

Reference: https://socket.io/docs/v4/client-initialization/#extraHeaders

@satpal-07
Copy link

satpal-07 commented Mar 30, 2021

Thanks @darrachequesne for your reply. I am using websockets only, I need to pass a token to backend from browser along with the websocket connection request and the token will be validated in a F5 server before the request allowed to hit the socket server. I am considering to use the query option. Is this something that will work?

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

@darrachequesne
Copy link
Member

@satpal-07 yes, this should totally work 👍

Please note that your token will be sent in the query parameters of the request, and will thus be URL-encoded.

@reghuramk
Copy link

reghuramk commented Sep 30, 2023

I do not think sending the access token inside a query params is a wise thing to do. Refer below link for reference.

https://stackoverflow.com/questions/32722952/is-it-safe-to-put-a-jwt-into-the-url-as-a-query-parameter-of-a-get-request

Instead you can send the accesstoken in the auth key.

Client

const socket = io('http://localhost:3000', {
	withCredentials: false,
	transports: ['websocket'],
	path: '/my-custom-path/',
	auth: {
		accessToken: 'abc'
	}
});

Server
You can access it inside the handshake object.

console.log(client.handshake.auth, 'handshake');

@Robbert-Brand
Copy link

Would it be an option for in-browser use, to load the token in the request body of the websocket message, instead of directly in the headers? That way, a reverse proxy or load balancer could move the request body to a header, which then could be used internally for load balancing, authentication, or other header-based handeling.

@darrachequesne
Copy link
Member

@Robbert-Brand unfortunately, the WebSocket API for the browser does not allow sending a request body within the HTTP upgrade request.

What could be done is send a first HTTP request, retrieve a cookie, and then open the WebSocket connection.

@darrachequesne
Copy link
Member

For future readers, to send some credentials when only using WebSocket, you should use the auth option:

const socket = io({
  transports: ['websocket'],
  auth: {
    token: 'some-token-value'
  }
});

Reference: https://socket.io/docs/v4/client-options/#auth

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

9 participants