Chatroom tutorial part 4

Authenticating JavaScript clients

Clients are authenticated using JWT authentication. The basic flow works like this:

  1. User receives an open event from Scaledrone.
  2. User sends the drone.clientId parameter to your JWT authentication server (such as a simple REST server).
  3. Your JWT server decides if the user is allowed to connect and what it has access to and creates a JSON Web Token (JWT).
  4. JWT server sends the token back to the user.
  5. User sends the token to Scaledrone.
  6. Scaledrone emits an authenticated event, the user can now publish and subscribe to rooms.
Turn on channel authentication from the channel admin page:

Creating a basic REST JWT server

JWT libraries for most languages can be found from jwt.io

This server listens to port 1234 and serves a token to users, allowing them to subscribe and publish only to room general-chat.

jwt_server.js
var express = require('express');
var jwt = require('jwt-simple');
var secret = 'secret_key';
var channel = 'channel_id';
var app = express();

function hasChannelAccess(req) {
  return true;
}


app.get('/jwt', function(req, res) {
  res.header('Access-Control-Allow-Origin', '*'); // for developing
  if (hasChannelAccess(req)) {
    console.log(req.query);
    var clientId = req.query.clientId;
    var payload = {
      client: clientId, // the client that wants to connect
      channel: channel, // channel_id the client want's to connect to
      permissions: {
        '^general-chat$': { /* Regex exact match to general-chat */
          publish: true, /* Allows publishing in general-chat */
          subscribe: true
        }
      },
      exp: Date.now() + 180000 // Client can use this token for 3 minutes (UTC0)
    };
    console.log(payload);
    var token = jwt.encode(payload, secret, 'HS256');
    res.send(token);
  } else {
    res.send(403, 'Sorry! You are not allowed.');
  }
});

app.listen(1234);
console.log('Server is running..');

Interacting with the JWT server from JavaScript

Next, lets do a GET request to the JWT server. Send the drone.clientId to the JWT server and get JSON Web Token as a reply. After the token has been sent to Scaledrone an authenticate event will be emitted.

script.js
var drone = new ScaleDrone('your_channel_id');

drone.on('open', function (error) {
  if (error) return console.error(error);

  getJWT(drone.clientId, function (token) {
    drone.authenticate(token);
  });
});

drone.on('authenticate', function (error) {
  if (error) return console.error(error);

  var room = drone.subscribe('general-chat');

  room.on('open', function (error) {
    if (error) return console.error(error);
    console.log('Connected to room');
  });

  room.on('data', addMessageToScreen);        
});

function onSubmitForm(event) {
  var nameEl = document.querySelector('.input.name')
    , contentEl = document.querySelector('.input.content');

  if (nameEl.value && contentEl.value) {
    sendMessageToScaleDrone(nameEl.value, contentEl.value);
    contentEl.value = '';
  }
}

function sendMessageToScaleDrone(name, content) {
  drone.publish({
    room: 'general-chat',
    message: {
      name: name,
      content: content
    }
  });
}

function addMessageToScreen(message) {
  var div = document.createElement('div');
  div.innerHTML = '<b>' + message.name + '</b>: ' + message.content;
  div.classList.add('message');
  document.querySelector('.text-area').appendChild(div);
}

// Do a GET request to the JWT server
function getJWT(clientId, callback) {
  console.log('Asking for JSON Web Token..');
  request = new XMLHttpRequest();
  request.open('GET', 'http://localhost:1234/jwt?clientId=' + clientId, true);
  request.onload = function() {
    if (this.status >= 200 && this.status < 400) {
      callback(this.response);
    } else {
      console.error('Unable to get JWT', this);
    }
  };
  request.onerror = function(error) {
    console.error('Unable to get JWT', error);
  };
  request.send();
}

You have now successfully authenticated the JavaScript client!

Using JWT to authenticate the REST API

In the last tutorial we sent a Basic Authorization header to authenticate the REST API requests. You can also set the JSON Web Token as a Bearer token to authenticate the REST API calls.