Support

How do I use a JWT to authenticate private videos?

The first step is to generate a public/private key pair and add the public half to our enterprise video CMS. If you haven’t done that step already, please see how do I create a JWT?. You use your private key to sign the token. That proves it was you that created it. As nobody else has access to your private key.

This part of the guide covers the header and the payload of your JWT.

You will need to specify these three values in your JWT header:

  1. algorithm: that is always RS256.

  2. expiresIn: this is a string specifying how long the JWT is valid for. For example 1h meaning one hour. Or 24h meaning twenty-four hours.

  3. keyid: this is the key ID we generated when you provided your public key to us earlier. For example abcdefg1234567.

You may optionally provide:

  1. subject: this is a single video ID if you would like your JWT to only be used to access that one video, rather than them all. For example uk1abcdefghi123.

The code below shows an example of making the most basic JWT. The only restriction we have placed is that it expires in one hour. We have used the NodeJS jsonwebtoken syntax but every language will be similar:

const jwt = require('jsonwebtoken')

// a PEM-encoded RSA PKCS#1 key:
let privateKey = fs.readFileSync('private.key')

let token = jwt.sign({}, privateKey, {
  algorithm: 'RS256',
  expiresIn: '1h',
  keyid: 'YOUR-KEY-ID',
})

The resulting JWT will be a long string of letters and numbers. It will look something like this (though not as colourful!)

Example JWT

You now append that JWT to requests for any video whose access has been set as authenticated as shown below (replacing VIDEO-ID and JWT-HERE).

A landing page link, sent by email, would look like this:

https://watch.vidbeo.com/VIDEO-ID?jwt=JWT-HERE

An iframe src, used for embedding a video on your own site, would look like this:

https://embed.vidbeo.com/VIDEO-ID?jwt=JWT-HERE

A HLS manifest, for when you want to use your own player, would look like this:

https://watch.vidbeo.com/VIDEO-ID/hls.m3u8?jwt=JWT-HERE

Note: Since we also allow authentication using a cookie, make sure you are signed out of our video CMS when testing these JWT-protected URLs. Else it may unexpectedly be allowed or denied due to the cookie being sent by your browser behind the scenes.

Payload

The payload is optional. You can think of it as containing additional rules for “only allow requests from …“.

You can provide up to five (if you need more, please ask) of:

  • ips
  • origins
  • countries

These claims operate using an implied AND. So if you specify multiple rules, the request will only be permitted if both are true.

For example to restrict your JWT to only be used from one of two IPs 1.2.3.4 or 2.3.4.5 you would set its payload (the first parameter) like this:

let token = jwt.sign(
  {
    access: {
      allow: {
        ips: ['1.2.3.4', '2.3.4.5'],
      },
    },
  },
  privateKey,
  {
    algorithm: 'RS256',
    expiresIn: '24h',
    keyid: 'YOUR-KEY-ID',
    subject: 'VIDEO-ID',
  }
)

Note: Some new sites have a Content Security Policy (CSP) that may block this from being sent to us. And so we have no way of knowing if the JWT is being used for a domain you actually do want to allow. And so to be safe, have to block the request. If you run into issues we can investigate.

This is how it works if you want to try out using an origin:

let token = jwt.sign(
  {
    access: {
      allow: {
        origins: ['https://www.your-site.com', 'https://another-site.com'],
      },
    },
  },
  privateKey,
  {
    algorithm: 'RS256',
    expiresIn: '24h',
    keyid: 'YOUR-KEY-ID',
    subject: 'VIDEO-ID',
  }
)

We also support using geo-fencing. Provide each country as a two-letter ISO_3166-1_alpha-2 code, in lower-case. For example to restrict your JWT to be used from Spain, you would use its international code of es:

let token = jwt.sign(
  {
    access: {
      allow: {
        countries: ['es'],
      },
    },
  },
  privateKey,
  {
    algorithm: 'RS256',
    expiresIn: '24h',
    keyid: 'YOUR-KEY-ID',
    subject: 'VIDEO-ID',
  }
)

Note: If you are using Web Crypto JavaScript to make your JWT, that requires your private key be in the newer PKCS#8 format. If your private key is not already (and so you get errors using it) you can convert it using a command like this:

openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in private.key -out private_pkcs8.key

If you have any questions, please email us to ask.

Updated: September 25, 2023