Skip to content

Authenticating with JSON Web Tokens (JWT)

Luke Duncalfe edited this page May 5, 2018 · 5 revisions

Generating JWT

Have a read about JWT to understand header, payload and signatures. There are JWT libraries for all common languages that help you generate them.

Expectations

nano-stream-ws has some expectations of the JWT you generate. Whichever library you use, you must be able to do the following:

  • Algorithm must be HMAC SHA256 ("HS256")
  • There must be an expiration time set
  • It must be signed with the same secret you pass to the nano-stream-ws executable
  • It can't be used more than once. If a client attempts to connect with the same token again it will be rejected, so a new token must be generated for each connection and user

An important note on the expiration time

Because the client only ever listens passively to the websocket stream from nano-stream-ws and never sends messages back, the value for the expiration time should be the unix time when the bearer of the token can no longer initialize a new connection. I recommend you set the expiration time to about 10 seconds into the future.

Example

There are JWT libraries for all common languages. We'll look at generating a valid JWT using the npm package jsonwebtoken running on a server:

const jwt = require('jsonwebtoken');

// jsonwebtoken defaults to using "HS256" for the algorithm,
// so we don't need to declare it anywhere.
//
// This token can only be used to establish a connection for 10 seconds
// after it was issued
const token = jwt.sign({}, 'my_secret', { expiresIn: 10 });
console.log(token);

An example output:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MjUzMzc5MjksImV4cCI6MzA1MDY3NTg2OH0.tfqls3_fV6RQnOfx4-PMed_E2XCttNFr0uppm_nclsw

Check that the tokens are being properly generated by pasting one into the jwt.io debugger and inspecting it.

Using JWTs in the connection to the websocket server

Your server should output the tokens into the HTML page that you give to your users. The token should be between <script> tags so it will be assigned as a JavaScript variable when the page loads. The JavaScript variable in the page can later be used by JavaScript when connecting to the websocket server.

For example, in PHP:

<script>var jwtToken = "<? echo $jwt_token ?>";</script>

Passing the token to the websocket server

Because the Websocket protocol doesn't allow setting headers, the token is passed to the server as part of the query string. The param name is t:

var exampleSocket = new WebSocket("ws://www.example.com/?t="+jwtToken);

// Log the stream to the console:
exampleSocket.onmessage = function (event) {
  console.log(event.data);
}

Troubleshooting

Any errors should be logged from your nano-stream-ws process. These are all the reasons for why a JWT connection might be rejected:

  • No token supplied (the t param in the URI)
  • Token was invalid (possibly because the secret was invalid - check the token your server is outputting against the jwt.io debugger)
  • Token has no expiration
  • Token has expired
  • Token has already been used by another client