Writing a backend to proxy SignalWire Video REST API

Even though SignalWire provides the platform for all video communications when you’re using the Video APIs, you still need to write some server-side logic to proxy the SignalWire REST APIs. Your server-side script should work to authenticate your users, manage their permissions, and relay the tokens from the SignalWire's Video REST APIs to the client's browser. The token has information like the room name, and the permissions for the token’s user. The JavaScript SDK running in the client's browser will then use the tokens to establish direct connection with the SignalWire servers.

Your server doesn't have to do much, as you'll see in code below:

require("dotenv").config();
const auth = {
  username: process.env.PROJECT_ID, // Project-ID
  password: process.env.API_KEY, // API token
};
const apiurl = process.env.SPACE;// <your username>.signalwire.com/api/video

const moderatorPermissions = [
  "room.list_available_layouts",
  "room.set_layout",
  "room.member.audio_mute",
  "room.member.audio_unmute",
  "room.member.deaf",
  "room.member.undeaf",
  "room.member.remove",
  "room.member.set_input_sensitivity",
  "room.member.set_input_volume",
  "room.member.set_output_volume",
  "room.member.video_mute",
  "room.member.video_unmute",
];
const normalPermissions = [
  "room.self.audio_mute",
  "room.self.audio_unmute",
  "room.self.video_mute",
  "room.self.video_unmute",
  "room.self.deaf",
  "room.self.undeaf",
  "room.self.set_input_volume",
  "room.self.set_output_volume",
  "room.self.set_input_sensitivity",
  "room.hide_video_muted",
  "room.show_video_muted",
];

// Basic express boilerplate
const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");
const axios = require("axios");

const app = express();
app.use(bodyParser.json());
app.use(cors());
// End basic express boilerplate



// Endpoint to request token for video call
app.post("/get_token", async (req, res) => {
  let { user_name, room_name, mod } = req.body;
  console.log("Name:", user_name, "Room:", room_name);
  if (mod) console.log("As Moderator");
  try {
    let token = await axios.post(
      apiurl + "/room_tokens",
      {
        user_name,
        room_name: room_name,
        permissions: mod
          ? [...normalPermissions, ...moderatorPermissions]
          : normalPermissions,
      },
      { auth }
    );

    token = token.data?.token;
    return res.json({ token });
  } catch (e) {
    console.log(e);
    return res.sendStatus(500);
  }
});

  app.listen(5000, () => {
    console.log("Server listening at port", 5000);
  });

The source above is all it takes to write a functional backend for SignalWire Video SDKs. At the most basic level, all it has to do is provide a single endpoint (here named /get_token) which takes the name of a room and the name of the person, and returns an JWT token. The client-side SDK will handle the rest.

Permissions

There are a few things to discuss in this code. First the two constants: normalPermissions and moderatorPermissions. SignalWire provides granular control over what each user is allowed to control in the video conference. Detailed description of these permissions live in the SignalWire API references, but they should be self-explanatory. How you categorise and use the permissions, or whether you choose to not use them is up to you. For this demo, we’ll use the permissions to create two levels of users: Normal users (guests) and Moderators. Moderators have almost all allowed permissions, while guests have the bare minimum permissions (like muting themselves or turning off their video).

Permission NameDescription
room.hide_video_mutedHide the videos of members with muted video.
room.show_video_mutedShow the videos of members with muted video.
room.list_available_layoutsGet a list of available layouts.
room.set_layoutSet the current layout.
room.member.audio_muteMute the audio of any member in the room.
room.member.audio_unmuteUnmute the audio of any member in the room.
room.member.deafDeaf the audio of any member in the room.
room.member.undeafUndeaf the audio of any member in the room.
room.member.removeRemove any member from the room.
room.member.set_input_sensitivitySet the audio input sensitivity of any member in the room.
room.member.set_input_volumeSet the audio input volume of any member in the room.
room.member.set_output_volumeSet the audio output volume of any member in the room.
room.member.video_muteMute the video of any member in the room.
room.member.video_unmuteUnmute the video of any member in the room.
room.self.audio_muteMute the audio of yourself.
room.self.audio_unmuteUnmute the audio of yourself.
room.self.deafDeaf the audio of yourself.
room.self.undeafUndeaf the audio of yourself.
room.self.set_input_sensitivitySet your own audio input sensitivity.
room.self.set_input_volumeSet your own audio input volume.
room.self.set_output_volumeSet your own audio output volume.
room.self.video_muteMute your own video.
room.self.video_unmuteUnmute your own video.

SignalWire Video REST API expects an array of permissions to be sent with the token request. If undefined, a default set of permissions will be used.

Authentication

Next, the definition of the auth object. To be able to access the SignalWire REST API, we need three key pieces of information. This is explained in detail in the Getting Started section, but to recap, they are:

Project ID: This UUID formatted string uniquely identifies the project that SignalWire will bill.

API Token: This JWT formatted string can be generated via the SignalWire Dashboard. You can generate tokens that only restrict access to a certain SignalWire product (like video, or messaging) to reduce the attack surface should the token leak. Keep this a secret, and make arrangements to ensure it doesn’t accidentally get pushed to GitHub or other public endpoints.

Space URL: This is a URL in the format {your username}.signalwire.com. You will use this URL to access all SignalWire REST APIs. For video, the URL is {your username}.signalwire.com/api/video.

The SignalWire REST APIs use basic authentication with the Project ID as username and the API Token as the password. Axios makes it easier by simply accepting an auth object, which it will concatenate and encode in base 64 to create a basic authentication token. The REST API endpoints are accessed through your Space URL. More information on the endpoints is documented in the SignalWire API reference.

Querying the SignalWire Video REST API

Now we're all set to query the SignalWire Video REST API for a token. We use Axios library in this example but any other library will do. The token we get will then be sent to the frontend.

let token = await axios.post(
    apiurl + "/room_tokens", {
        user_name,
        room_name: room_name,
        permissions: mod ? [...normalPermissions, ...moderatorPermissions] : normalPermissions,
    }, {
        auth
    }
);

Demo:

This backend is enough to serve our zoom clone for our project.

It is hosted at https://codesandbox.io/s/lr3ti if you would like to tinker with it.


Did this page help you?