371

Looks like it's easy to add custom HTTP headers to your websocket client with any HTTP header client which supports this, but I can't find how to do it with the web platform's WebSocket API.

Anyone has a clue on how to achieve it?

var ws = new WebSocket("ws://example.com/service");

Specifically, I need to be able to send an HTTP Authorization header.

Domenic
  • 110,262
  • 41
  • 219
  • 271
Julien Genestoux
  • 31,046
  • 20
  • 66
  • 93
  • 28
    I think a good solution is to allow the WebSocket to connect without authorization, but then block and wait on the server to recieve authorization from the webSocket which will transmit authorization information in its onopen event. – Motomotes Dec 28 '15 at 15:57
  • The suggestion by @Motes seems to be the best fit. It was very easy to make an authorization call from onOpen which allows you to accept/reject the socket based on the authorization response. I originally attempted sending auth token in Sec-WebSocket-Protocol header but that feels like a hack. – BatteryAcid Oct 29 '17 at 03:59
  • 1
    @Motes Hi, could you explain the "block and wait on the server" part ? you mean something like don't process any messages till there's a "auth" message ? – Himal Aug 18 '19 at 04:44
  • @Himal, yes the server design must not send data or accept any other data than authorization in the beginning of the connection. – Motomotes Aug 18 '19 at 10:37
  • @Motes Thanks for the reply. I was bit confused by the blocking part, becasue to my understanding you can't block the initial `connect` request. I'm using Django channels on the back end and I've designed it to accept the connection on `connect` event. it then sets an "is_auth" flag in the `receive` event (if it sees a valid auth message). if the is_auth flag isn't set and it's not an auth message then it closes the connection. – Himal Aug 18 '19 at 14:40
  • I guess by block I was implying reject any other traffic, or that is as to say do the auth yourself and reject any failed auth like you say. – Motomotes Aug 18 '19 at 21:14
  • @Motes Allowing a websocket creation by deferring auth has risks such as malicious attacks that can overload the server with lot of unauthenticated socket creations. – Ashwin Prabhu Jun 29 '22 at 09:29
  • @AshwinPrabhu Any open socket is vulnerable to DDOS. Doing auth with one's own code or being a code monkey dependent on another cut and paste framework doesn't change that. I didn't say use Django, I said construe the authentication scheme oneself, having Django change or extend the websocket protocol to do the auth for one has no unique relevance to DDOS vulnerability. The socket should of course be closed if the client does not authenticate. – Motomotes Jul 06 '22 at 10:08
  • @Motes Essentially you mean to say you would run a background GC to sweep through all the open but unauthenticated connections? I was just calling out a potential risk in the solution that requires waiting until the first message to invalidate open connections. Not sure where Django enters this argument - maybe that's what you work with. – Ashwin Prabhu Jul 09 '22 at 14:57
  • "Essentially you mean to say you would run a background GC to sweep through all the open but unauthenticated connections?" No, not even close. – Motomotes Jul 12 '22 at 11:56
  • Not an answer, but relevant to this discussion is this issue in the standards repo: https://github.com/whatwg/websockets/issues/16 where the implementers talk about why they're resisting putting in such support. Since it's been open for 5 years now, I can't see it changing any time soon. The advice over there basically boils down to: "put the token in the URL for the handshake, or do a post-connect message to provide the token." There is also surprise that people aren't (mis)using the Sec-WebSocket-Protocol header even though that clearly isn't the design intent for that header. – MrCranky Nov 30 '22 at 11:46
  • It is nothing less than intolerable how basic security in web technologies gets treated as a nice-to-have by standardization mechanisms. There should be one obvious way to do basic security. Lots of seriously flawed solutions floating around because there is no obvious way to do this, lots of choices to choose from, and every programmer needs to become a security expert just to do basic things safely. It is not okay. The industry needs to pull up its pants on this. – Teekin Dec 26 '22 at 15:18

16 Answers16

365

Updated 2x

Short answer: No, only the path and protocol field can be specified.

Longer answer:

There is no method in the JavaScript WebSockets API for specifying additional headers for the client/browser to send. The HTTP path ("GET /xyz") and protocol header ("Sec-WebSocket-Protocol") can be specified in the WebSocket constructor.

The Sec-WebSocket-Protocol header (which is sometimes extended to be used in websocket specific authentication) is generated from the optional second argument to the WebSocket constructor:

var ws = new WebSocket("ws://example.com/path", "protocol");
var ws = new WebSocket("ws://example.com/path", ["protocol1", "protocol2"]);

The above results in the following headers:

Sec-WebSocket-Protocol: protocol

and

Sec-WebSocket-Protocol: protocol1, protocol2

A common pattern for achieving WebSocket authentication/authorization is to implement a ticketing system where the page hosting the WebSocket client requests a ticket from the server and then passes this ticket during WebSocket connection setup either in the URL/query string, in the protocol field, or required as the first message after the connection is established. The server then only allows the connection to continue if the ticket is valid (exists, has not been already used, client IP encoded in ticket matches, timestamp in ticket is recent, etc). Here is a summary of WebSocket security information: https://devcenter.heroku.com/articles/websocket-security

Basic authentication was formerly an option but this has been deprecated and modern browsers don't send the header even if it is specified.

Basic Auth Info (Deprecated - No longer functional):

NOTE: the following information is no longer accurate in any modern browsers.

The Authorization header is generated from the username and password (or just username) field of the WebSocket URI:

var ws = new WebSocket("ws://username:password@example.com")

The above results in the following header with the string "username:password" base64 encoded:

Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

I have tested basic auth in Chrome 55 and Firefox 50 and verified that the basic auth info is indeed negotiated with the server (this may not work in Safari).

Thanks to Dmitry Frank's for the basic auth answer

nornagon
  • 15,393
  • 18
  • 71
  • 85
kanaka
  • 70,845
  • 23
  • 144
  • 140
  • 79
    I've come across the same problem. Too bad that these standards are so poorly integrated. You'd expect that they look at the XHR API to find requirements (since WebSockets and XHR are related) for the WebSockets API, but it seems they are just developing the API on an island by itself. – eleotlecram May 01 '12 at 14:26
  • 4
    @eleotlecram, join the HyBi working group and propose it. The group is open to the public and there is ongoing work for subsequent versions of the protocol. – kanaka May 01 '12 at 18:59
  • Would it be a bad idea to use the Protocol header values to send (for example) an authorisation hash? Reading here - http://stackoverflow.com/questions/7363095/javascript-and-websockets-using-specific-protocol - it doesn't feel like a bad idea, but I do wonder what the implications are. – Charlie Jun 04 '14 at 16:20
  • 8
    @Charlie: if you fully control the server, that's one option. The more common approach to is generate a ticket/token from your normal HTTP server and then have the client send the ticket/token (either as a query string in the websocket path or as the first websocket message). The websocket server then validates that the ticket/token is valid (hasn't expired, hasn't already been used, coming from same IP as when created, etc). Also, I believe most websockets clients support basic auth (may not be enough for you though). More info: https://devcenter.heroku.com/articles/websocket-security – kanaka Jun 04 '14 at 17:57
  • @eleotiecram According to rfc6455: WebSocket Protocol is designed to supersede existing bidirectional communication technologies that use HTTP as a transportlayer to benefit from existing infrastructure (proxies, filtering,authentication). [...........] The WebSocket Protocol attempts to address the goals of existing bidirectional HTTP technologies in the context of the existing HTTP infrastructure; as such, it is designed to work over HTTP ports 80 and 443 as well as to support HTTP proxies and intermediaries, even if this implies some complexity specific to the current environment. –  Sep 14 '16 at 18:47
  • 3
    I guess its by design. I am under the impression that the implementation is intentionally borrowing from HTTP but keep them separated as much as possible by design. The text in the specificatio continues: "However, the design does not limit WebSocket to HTTP, and future implementations could use a simpler handshake over a dedicated port without reinventing the entire protocol. This last point is important because the traffic patterns of interactive messaging do not closely match standard HTTP traffic and can induce unusual loads on some components." –  Sep 14 '16 at 18:54
  • 2016 and this is still the case :( – shabunc Oct 07 '16 at 15:04
  • If we cannot add a custom header, can we at least modify a non custom header, for instance, 'Cookie'? – user3631341 Dec 09 '16 at 07:07
  • There is a way to set Basic Authorization HTTP header, see my answer. – Dmitry Frank Jan 07 '17 at 13:36
  • 4
    Unfortunately this doesn't seem to work in Edge. Thanks, MS :/ – sibbl Feb 21 '17 at 11:07
  • `ws://username:password@example.com` this pattern doesn't work in Safari, but works in chrome, ff – Sasi Varunan Jul 25 '17 at 13:58
  • [how do i set a "connection" header?](https://stackoverflow.com/questions/53798531/error-during-websocket-handshake-connection-header-is-missing) thanks – oldboy Dec 16 '18 at 02:35
  • 1
    Does Basic auth still work? I've tested Chrome and Firefox and there is no Authorization header. – Kegan Thorrez Jan 30 '19 at 23:53
  • 1
    Basic auth won't work anymore as the approach is deprecated. https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#Access_using_credentials_in_the_URL – pkgajulapalli Feb 07 '19 at 10:12
  • When I tried to use "Sec-WebSocket-Protocol" in chrome, I got `WebSocket: Error during WebSocket handshake: Sent non-empty 'Sec-WebSocket-Protocol' header but no response was received` error. – pkgajulapalli Feb 07 '19 at 10:13
  • @pkgajulapalli I've updated the answer to show that basic auth is deprecated. The reason you get that error is because the server needs to support the protocol field and answer with the protocol value that was selected. – kanaka Feb 07 '19 at 17:30
  • @kanaka do you have a link to where it says basic auth is deprecated? – felixfbecker Mar 07 '19 at 19:41
  • 3
    @shabunc 2019 and this is still the case :( – andrhamm Jul 19 '19 at 00:44
  • 2
    I'm working around the limitations and leveraging the protocol field as an authentication field. No different than using `Authentication: Bearer TOKEN`... just a different header to observe on before allowing the the WS to open up... if anyone needs details on this approach, I can paste my solution as a new answer – Matt Lo Apr 06 '22 at 02:58
  • @MattLo Does piggybacking auth token as sec protocol header work across browsers for desktop and mobile? – Ashwin Prabhu Jul 09 '22 at 15:01
  • @AshwinPrabhu yep, any version the security protocol header is available as an input, you can hack it to add w/e data you want in there – Matt Lo Jul 15 '22 at 18:47
  • @kanaka What are the pros/cons of sending the token in the params or first message? Will configuring it in the params send it in every subsequent message, as you can't change this after connection? I imagine if that's the case then that's a downer if throughput is an issue. – Daniel Gerson Oct 09 '22 at 12:33
  • 1
    @DanielGerson The URL and query parameters and other HTTP headers are only sent once when the connection is established. Where you send that really depends on what system is going to make use of it. WebSocket connections are often passed through a front-end to the actual WebSocket server. If the front-end needs the info then you would want it in the params or headers. If the backend, then either would work (depending on how the pass-through works). – kanaka Oct 12 '22 at 14:05
87

More of an alternate solution, but all modern browsers send the domain cookies along with the connection, so using:

var authToken = 'R3YKZFKBVi';

document.cookie = 'X-Authorization=' + authToken + '; path=/';

var ws = new WebSocket(
    'wss://localhost:9000/wss/'
);

End up with the request connection headers:

Cookie: X-Authorization=R3YKZFKBVi
Tim
  • 2,805
  • 25
  • 21
  • 2
    This does seem like the best way to pass access tokens on connection. At the moment. – cammil Feb 23 '20 at 10:58
  • 10
    what if the WS server URI is different from client URI? – Danish May 07 '20 at 00:11
  • 13
    @Danish Well then that doesn't work, since you cannot set cookies for other domains client side – Tofandel Jul 03 '20 at 20:12
  • 5
    But, you can set up an HTTP service that sets a session cookie on the relevant path, and call that before starting your websocket. Call, say, `https://example.com/login`, and have the response set a cookie on `/wss` then `new WebSocket("wss://example.com/wss")` will start its handshake request with the relevant cookie. Note that the devtools might not show the cookie, but it should still be sent. – Coderer Jul 09 '20 at 12:52
  • 12
    Websocket requests are not subject to the same origin policy. Sending authentication as a cookie will open up your application to hijacking. See https://christian-schneider.net/CrossSiteWebSocketHijacking.html – Declan Shanaghy Oct 19 '20 at 18:43
  • 5
    Christian Schneider (the author of the article above) suggests using CSRF-Tokens to protect initial HTTP handshake, when using Authentication Cookie: `ws = new WebSocket("wss://example.com/wss?csrftoken=")` – Alex Buchatski Mar 30 '21 at 10:31
  • 3
    You could also simply check the origin. – iwaduarte May 07 '21 at 19:11
  • @Coderer could explain how would I achieve this pattern? I am trying to integrate with cookies but those different domains will not allow it (localhost development) – iwaduarte May 07 '21 at 22:25
  • 1
    The cookie has to be set on the domain that you're connecting to, not the Origin where your script is served from. That's why I suggested having `example.com/login` return a `Set-Cookie: Session=xyz123`. Once `example.com` has a session cookie associated with it, `new WebSocket("wss://example.com/wss/")` will send the `Session` cookie along with the handshake. As Declan points out, though, this can lead to hijacking. If you control the backend, it'd be better to send credentials over the socket connection. – Coderer May 11 '21 at 08:05
  • 2
    Underrated comment by @Coderer: `Note that the devtools might not show the cookie, but it should still be sent.` I've confirmed that the dev-tools do not show these cookies on websocket requests/connections! Annoying as this caused a lot of time lost thinking I was doing something wrong. – Venryx Jul 19 '21 at 08:26
  • @Venryx +1, devtools on Firefox/Chrome/Opera do not show any cookie header but I will have to assume it is indeed not sent at all (contrary to Coderer saying "it should be sent", as I was not able to reproduce this attack on different domains/servers/sockets I own. Tested on mobile Android Chrome as well : no exploit. – Musa Dec 28 '21 at 20:11
  • @Musa Odd; in my case, the dev-tools did not show the cookie being sent on the WS connection, yet it was in fact sent (I know because my NodeJS server was receiving the auth data from the WS connection). There must be some difference of the protocol used, the server tech stack, or something of that sort. – Venryx Dec 29 '21 at 18:44
42

Sending Authorization header is not possible.

Attaching a token query parameter is an option. However, in some circumstances, it may be undesirable to send your main login token in plain text as a query parameter because it is more opaque than using a header and will end up being logged whoknowswhere. If this raises security concerns for you, an alternative is to use a secondary JWT token just for the web socket stuff.

Create a REST endpoint for generating this JWT, which can of course only be accessed by users authenticated with your primary login token (transmitted via header). The web socket JWT can be configured differently than your login token, e.g. with a shorter timeout, so it's safer to send around as query param of your upgrade request.

Create a separate JwtAuthHandler for the same route you register the SockJS eventbusHandler on. Make sure your auth handler is registered first, so you can check the web socket token against your database (the JWT should be somehow linked to your user in the backend).

  • This was the only secure solution I could come up with for API Gateway websockets. Slack does something similar with their RTM API and they have a 30 second timeout. – andrhamm Jul 19 '19 at 00:42
  • 1
    Note that if you're creating a websocket connection from node-js (as opposed to the browser), sending an authorization header is possible. See here: https://github.com/apollographql/apollo-client/issues/3967#issuecomment-882338049 – Venryx Jul 19 '21 at 08:10
39

HTTP Authorization header problem can be addressed with the following:

var ws = new WebSocket("ws://username:password@example.com/service");

Then, a proper Basic Authorization HTTP header will be set with the provided username and password. If you need Basic Authorization, then you're all set.


I want to use Bearer however, and I resorted to the following trick: I connect to the server as follows:

var ws = new WebSocket("ws://my_token@example.com/service");

And when my code at the server side receives Basic Authorization header with non-empty username and empty password, then it interprets the username as a token.

Dmitry Frank
  • 10,417
  • 10
  • 64
  • 114
  • 15
    I am trying the solution suggested by you. But I am not able to see the Authorization header being added to my request. I have tried it using different browsers e.g. Chrome V56, Firefox V51.0 I am running my server on my localhost. so the websocket url is "ws://myusername:mypassword@localhost:8080/mywebsocket". Any idea what might be wrong? Thanks – LearnToLive Mar 11 '17 at 21:15
  • 6
    Is it safe to transfer token through url? – Ilya Loskutov May 04 '17 at 18:02
  • 1
    @Mergasov same thing is questionable for Basic Authentication right? – Govinnage Rasika Perera May 25 '17 at 06:27
  • 1
    Wouldn't the basic authentication headers be hidden if secure connection is used, while the URL would be open to everybody snooping? – rslite Jun 04 '17 at 03:02
  • 2
    Empty/ignored username and non-empty password as token might be better because usernames might get logged. – AndreKR Jun 22 '17 at 01:28
  • 9
    I agree with @LearnToLive - I used this with wss (e.g. `wss://user:password@myhost.com/ws`) and got no `Authorization` header on the server side (using Chrome version 60) – user9645 Aug 04 '17 at 13:59
  • 1
    @rslite In a secure connection, everything including the URL is hidden inside of secure tunnel. – Ajay M Nov 08 '17 at 05:39
  • 6
    I have the same issue as @LearnToLive and @user9645; neither chrome nor firefox are adding the authorization header when the URI is in the `wss://user:pass@host` format. Is this not supported by browsers, or is something going wrong with the handshake? – David Kaczynski Feb 02 '18 at 20:42
  • 1
    same as @DavidKaczynski Anyone know why? Maybe new version drop the support? – Altiano Gerung Mar 22 '18 at 08:24
  • 1
    @user9645, that is incorrect! The URL is not encrypted. Even the same in HTTPS. – bman Apr 10 '18 at 03:21
  • 14
    The use of these urls `http://username:password@example.com` is depreciated. https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication. Maybe thats the reason it does not work with websockets either! – Dachstein Aug 19 '18 at 18:14
29

You can not send custom header when you want to establish WebSockets connection using JavaScript WebSockets API. You can use Subprotocols headers by using the second WebSocket class constructor:

var ws = new WebSocket("ws://example.com/service", "soap");

and then you can get the Subprotocols headers using Sec-WebSocket-Protocol key on the server.

There is also a limitation, your Subprotocols headers values can not contain a comma (,) !

wonea
  • 4,783
  • 17
  • 86
  • 139
Saeed Zarinfam
  • 9,818
  • 7
  • 59
  • 72
29

You cannot add headers but, if you just need to pass values to the server at the moment of the connection, you can specify a query string part on the url:

var ws = new WebSocket("ws://example.com/service?key1=value1&key2=value2");

That URL is valid but - of course - you'll need to modify your server code to parse it.

  • 31
    need to be careful with this solution, the query string may be intercepted, logged in proxies etc. so passing sensitive info (users / password / authentication tokens) this way won't be secure enough. – Nir Apr 23 '17 at 13:46
  • 6
    @Nir with WSS the querystring should probably be safe – Sebastien Lorber May 29 '17 at 14:49
  • 12
    ws is plain text. Using ws protocol anything can be intercepted. – Gabriele Carioli May 30 '17 at 15:05
  • 1
    @SebastienLorber it is not safe to use query string it is not being encrypted the same applies to HTTPS, but since "ws://..." protocol is used, it really doesn't matter. – Lu4 Sep 20 '17 at 00:32
  • 16
    @Lu4 the query string is encrypted, but there are a host of other reasons not to add sensitive data as URL query parameters https://stackoverflow.com/questions/499591/are-https-urls-encrypted/499594#499594 & https://blog.httpwatch.com/2009/02/20/how-secure-are-query-strings-over-https/ as refs –  Nov 27 '17 at 19:53
  • @user484261 This comment is heavily underrated. – Jordan Breton Oct 05 '21 at 15:53
21

For those still struggling in 2021, Node JS global web sockets class has an additional options field in the constructor. if you go to the implementation of the the WebSockets class, you will find this variable declaration. You can see it accepts three params url, which is required, protocols(optional), which is either a string, an array of strings or null. Then a third param which is options. our interest, an object and (still optional). see ...

declare var WebSocket: {
    prototype: WebSocket;
    new (
        uri: string,
        protocols?: string | string[] | null,
        options?: {
            headers: { [headerName: string]: string };
            [optionName: string]: any;
        } | null,
    ): WebSocket;
    readonly CLOSED: number;
    readonly CLOSING: number;
    readonly CONNECTING: number;
    readonly OPEN: number;
};

If you are using a Node Js library like react , react-native. here is an example of how you can do it.

 const ws = new WebSocket(WEB_SOCKETS_URL, null, {
    headers: {
      ['Set-Cookie']: cookie,
    },
  });

Notice for the protocols I have passed null. If you are using jwt, you can pass the Authorisation header with Bearer + token

Disclaimer, this might not be supported by all browsers outside the box, from the MDN web docs you can see only two params are documented. see https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/WebSocket#syntax

Dharman
  • 30,962
  • 25
  • 85
  • 135
Peter Mugendi
  • 565
  • 6
  • 15
6

Totally hacked it like this, thanks to kanaka's answer.

Client:

var ws = new WebSocket(
    'ws://localhost:8080/connect/' + this.state.room.id, 
    store('token') || cookie('token') 
);

Server (using Koa2 in this example, but should be similar wherever):

var url = ctx.websocket.upgradeReq.url; // can use to get url/query params
var authToken = ctx.websocket.upgradeReq.headers['sec-websocket-protocol'];
// Can then decode the auth token and do any session/user stuff...
Ryan Weiss
  • 1,308
  • 1
  • 14
  • 36
  • 7
    Doesn't this just pass your token in the section where your client is supposed to request one or more specific protocols? I can get this working, no problem too, but I decided not to do this and rather do what Motes suggested and block until the auth token is sent on the onOpen(). Overloading the protocol request header seems wrong to me, and as my API is for public consumption, I think it is going to be kinda confusing for consumers of my API. – Jay Jun 27 '17 at 09:57
5

In my situation (Azure Time Series Insights wss://)

Using the ReconnectingWebsocket wrapper and was able to achieve adding headers with a simple solution:

socket.onopen = function(e) {
    socket.send(payload);
};

Where payload in this case is:

{
  "headers": {
    "Authorization": "Bearer TOKEN",
    "x-ms-client-request-id": "CLIENT_ID"
}, 
"content": {
  "searchSpan": {
    "from": "UTCDATETIME",
    "to": "UTCDATETIME"
  },
"top": {
  "sort": [
    {
      "input": {"builtInProperty": "$ts"},
      "order": "Asc"
    }], 
"count": 1000
}}}
Bicameral Mind
  • 799
  • 5
  • 9
  • It doesn't look like generic way to pass custom headers as don't see an option in their [API](https://github.com/pladaria/reconnecting-websocket#available-options). Is it a generic way or works only with Azure and some server side configuration? – Naga Kiran Apr 18 '21 at 16:38
  • This might be a decent enough work around for some, but it's worth noting that this will add a lot of IO for particularly chatty use-cases (the headers are sent every request). – Michael Fry Mar 21 '22 at 19:54
4

The recommended way to do this is through URL query parameters

// authorization: Basic abc123
// content-type: application/json
let ws = new WebSocket(
  "ws://example.com/service?authorization=basic%20abc123&content-type=application%2Fjson"
);

This is considered a safe best-practice because:

Adonis Gaitatzis
  • 3,189
  • 26
  • 24
2

to all future debugger - until today i.e 15-07-21

Browser also don't support sending customer headers to the server, so any such code

    import * as sock from 'websocket'
    const headers = {
        Authorization: "bearer " + token
    };
    console.log(headers);

    const wsclient = new sock.w3cwebsocket(
        'wss://' + 'myserver.com' + '/api/ws',
        '',
        '',
        headers,
        null
    );

This is not going to work in browser. The reason behind that is browser native Websocket constructor does not accept headers.

You can easily get misguided because w3cwebsocket contractor accepts headers as i have shown above. This works in node.js however.

TARJU
  • 1,785
  • 1
  • 14
  • 16
0

What I have found works best is to send your jwt to the server just like a regular message. Have the server listening for this message and verify at that point. If valid add it to your stored list of connections. Otherwise send back a message saying it was invalid and close the connection. Here is the client side code. For context the backend is a nestjs server using Websockets.

  socket.send(
      JSON.stringify({
        event: 'auth',
        data: jwt
      })
    );
0

I've tried these two approaches and neither worked, hopefully this will save you time:

  1. Implement websockets using fetch and streams api Is it possible to implement websockets in Javascript with Streams api?
  2. Use WebAssembly instead of javascript Feasibility of using WebAssembly to implement a WebSockets Client
sevzas
  • 701
  • 2
  • 5
  • 13
-2

My case:

  • I want to connect to a production WS server a www.mycompany.com/api/ws...
  • using real credentials (a session cookie)...
  • from a local page (localhost:8000).

Setting document.cookie = "sessionid=foobar;path=/" won't help as domains don't match.

The solution:

Add 127.0.0.1 wsdev.company.com to /etc/hosts.

This way your browser will use cookies from mycompany.com when connecting to www.mycompany.com/api/ws as you are connecting from a valid subdomain wsdev.company.com.

Max Malysh
  • 29,384
  • 19
  • 111
  • 115
-4

You can pass the headers as a key-value in the third parameter (options) inside an object. Example with Authorization token. Left the protocol (second parameter) as null


ws = new WebSocket(‘ws://localhost’, null, { headers: { Authorization: token }})

Edit: Seems that this approach only works with nodejs library not with standard browser implementation. Leaving it because it might be useful to some people.

Nodens
  • 354
  • 1
  • 3
  • 11
  • 3
    Had my hopes up for a sec. There doesn't appear to be an overload taking a 3rd param in WebSocket ctor. – Levitikon Dec 18 '19 at 14:18
  • 1
    Got the idea from wscat code. https://github.com/websockets/wscat/blob/master/bin/wscat line 261 wich uses the ws package. Thought this was an standard usage. – Nodens Jan 16 '20 at 11:29
  • 3
    This doesn't work for client side and at the server this answer seems irrelevant. – iwaduarte May 07 '21 at 22:25
-6

Technically, you will be sending these headers through the connect function before the protocol upgrade phase. This worked for me in a nodejs project:

var WebSocketClient = require('websocket').client;
var ws = new WebSocketClient();
ws.connect(url, '', headers);
George
  • 449
  • 3
  • 10
  • 5
    This is for the websocket client in npm (for node). https://www.npmjs.com/package/websocket Overall this would be exactly what I am looking for, but in the browser. – arnuschky Aug 16 '17 at 22:50
  • 3
    It's downvoted because this headers parameter in on the WebSocket protocol layer, and the question is about HTTP headers. – Toilal Nov 30 '17 at 13:49
  • "`headers` should be either null or an object specifying additional arbitrary HTTP request headers to send along with the request." from [WebSocketClient.md](https://github.com/theturtle32/WebSocket-Node/blob/master/docs/WebSocketClient.md#connectrequesturl-requestedprotocols-origin-headers-requestoptions); therefore, the `headers` here is HTTP layer. – momocow Oct 28 '18 at 07:41
  • Also, anyone who wants to provide custom headers should keep in mind the function signature of the `connect` method, described as `connect(requestUrl, requestedProtocols, [[[origin], headers], requestOptions])`, i.e. the `headers` should be provided along with `requestOptions`, for example, `ws.connect(url, '', headers, null)`. Only the `origin` string can be ignored in this case. – momocow Oct 28 '18 at 07:47
  • This solution only works for the `ws` nodejs client – alxpez Sep 29 '21 at 10:52