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 JSON API.
Yet, it seems that there should be support these headers in the spec.
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.
This question is related to
javascript
http
header
websocket
HTTP Authorization header problem can be addressed with the following:
var ws = new WebSocket("ws://username:[email protected]/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://[email protected]/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.
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).
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.
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 (,
) !
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.
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...
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
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);
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
}}}
My case:
www.mycompany.com/api/ws
...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
.
Source: Stackoverflow.com