3

I need a javascript library to connect to my web-socket server which is implemented using python twisted. I tried Native javascript web-socket client but it doesn’t have the option to pass custom headers as per this link. My web-socket server does authentication by taking auth_token from handshake header as in Oauth2 standard. Is there any javascript library available for web-socket clients which allows to pass custom header while connecting ?

Community
  • 1
  • 1
Bill Goldberg
  • 1,699
  • 5
  • 26
  • 50

1 Answers1

6

I'm sorry to be the bearer of bad news... but - as mentioned both in the question you are referencing and as you can learn from the standard Websocket API (this isn't an external library, it's what comes with the browser)... you cannot set custom headers for websocket connections.

The WebSocket(url, protocols) constructor takes one or two arguments. The first argument, url, specifies the URL to which to connect. The second, protocols, if present, is either a string or an array of strings. ... Each string in the array is a subprotocol name. The connection will only be established if the server reports that it has selected one of these subprotocols. ...

But, all is not lost.

Since this is YOUR websocket server, you have options:

  1. I'm pretty sure that OAuth2 uses the token as a parameter for a GET or POST request and NOT as a custom header. This means that (maybe) you can pass the token as part of the connection string, i.e.:

     websocket = new WebSocket('wss://my.server.com/?access_token=secret_acess_token');
    

    Passing the session token like so might not be ideal and could pose a security risk... so I would go with the second options here:

  2. New websocket connections (unless my browsers are special) are initiated with the same cookies that the main connection was established with - this means that all the cookies and session data from the Http layer is accessible to the websocket layer....

    So, It's possible to set a unique cookie - or, even better (assuming your http and websocket share the same codebase and work well together), set an authentication token within a server-side session storage - and use that data to authenticate a connection or to refuse it.

Since I'm no Python expert, here's a quick demo using Ruby's Plezi framework (I'm the author):

require 'plezi'

class DemoCtrl
   # this is the Http index page response
   def index
      response.write "#{cookies[:notice]}\n\n" if cookies[:notice] && (cookies[:notice] = nil).nil?
      #returning a string automatically appends it to the response.
      "We have cookies where we can place data:\n#{request.cookies.to_s}\n"
   end
   # the login page
   def login
      cookies[:my_token] = "a secret token"
      cookies[:notice] = "logged in"
      redirect_to :index
   end
   # the logout page
   def logout
      cookies[:my_token] = nil
      cookies[:notice] = "logged out"
      redirect_to :index
   end
   # a Plezi callback, called before a websocket connection is accepted.
   # it's  great place for authentication.
   def pre_connect
      puts "Websocket connections gave us cookies where we can place data:\n#{request.cookies.to_s}\n"
      return false unless cookies.to_s[:my_token] == "a secret token"
      # returning true allows the connection to be established
      true
   end
   def on_message data
      puts "echoing #{data}"
      response << "echo: #{data}"
   end
end

# setup the route to our demo
Plezi.route '/', DemoCtrl
# Plezi will start once the script is finished.
# if you are running this in irb, use:
exit

visit: http://loaclhost:3000/

to try and initiate a websocket, open up the web inspector and run the following script in the console:

ws = new WebSocket("ws://localhost:3000/"); ws.onopen = function(e) { console.log("open"); }; ws.onmessage = function(e) { console.log(e.data);};

ws.send("Go Bears");

This should FAIL, because we didn't authenticate yet...

visit http://loaclhost:3000/login and try again.

Now it should work.

Try http://loaclhost:3000/logout if you feel like it.

Community
  • 1
  • 1
Myst
  • 18,516
  • 2
  • 45
  • 67
  • 1
    Thanks Myst for the reply. Right now I managed this with workaround. Just used the provision to pass more than one sub-protocol for passing auth_token. And server will check the sub-protocol which is passed in case of no token found in header. – Bill Goldberg Nov 06 '15 at 13:56