Introduction
To add an extra level of protection when accessing your video library, or to apply user-level restrictions for your content, you can pass a JSON Web Token (JWT) with your call to the Brightcove Playback API. To create the token, follow these steps:
Generate public-private key pair
The publisher will generate a public-private key pair and provide the public key to Brightcove. The private key is used by the publisher to sign tokens, and is not shared with Brightcove.
There are many ways to generate the public-private key pair. Here are some examples:
Example bash script:
Example script to generate the key pair:
#!/bin/bash
set -euo pipefail
NAME=${1:-}
test -z "${NAME:-}" && NAME="brightcove-playback-auth-key-$(date +%s)"
mkdir "$NAME"
PRIVATE_PEM="./$NAME/private.pem"
PUBLIC_PEM="./$NAME/public.pem"
PUBLIC_TXT="./$NAME/public_key.txt"
ssh-keygen -t rsa -b 2048 -m PEM -f "$PRIVATE_PEM" -q -N ""
openssl rsa -in "$PRIVATE_PEM" -pubout -outform PEM -out "$PUBLIC_PEM" 2>/dev/null
openssl rsa -in "$PRIVATE_PEM" -pubout -outform DER | base64 > "$PUBLIC_TXT"
rm "$PRIVATE_PEM".pub
echo "Public key to saved in $PUBLIC_TXT"
Run the script:
$ bash keygen.sh
Example using Go
Example using the Go programming language to generate the key pair:
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"flag"
"fmt"
"io/ioutil"
"os"
"path"
"strconv"
"time"
)
func main() {
var out string
flag.StringVar(&out, "output-dir", "", "Output directory to write files into")
flag.Parse()
if out == "" {
out = "rsa-key_" + strconv.FormatInt(time.Now().Unix(), 10)
}
if err := os.MkdirAll(out, os.ModePerm); err != nil {
panic(err.Error())
}
priv, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err.Error())
}
privBytes := x509.MarshalPKCS1PrivateKey(priv)
pubBytes, err := x509.MarshalPKIXPublicKey(priv.Public())
if err != nil {
panic(err.Error())
}
privOut, err := os.OpenFile(path.Join(out, "private.pem"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
panic(err.Error())
}
if err := pem.Encode(privOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: privBytes}); err != nil {
panic(err.Error())
}
pubOut, err := os.OpenFile(path.Join(out, "public.pem"), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
panic(err.Error())
}
if err := pem.Encode(pubOut, &pem.Block{Type: "PUBLIC KEY", Bytes: pubBytes}); err != nil {
panic(err.Error())
}
var pubEnc = base64.StdEncoding.EncodeToString(pubBytes)
var pubEncOut = path.Join(out, "public_key.txt")
if err := ioutil.WriteFile(pubEncOut, []byte(pubEnc+"\n"), 0600); err != nil {
panic(err.Error())
}
fmt.Println("Public key saved in " + pubEncOut)
}
Example using node.js
Example using node.js to generate the key pair:
var crypto = require("crypto");
var fs = require("fs");
var now = Math.floor(new Date() / 1000);
var dir = "rsa-key_" + now;
fs.mkdirSync(dir);
crypto.generateKeyPair(
"rsa",
{modulusLength: 2048},
(err, publicKey, privateKey) => {
fs.writeFile(
dir + "/public.pem",
publicKey.export({ type: "spki", format: "pem" }),
err => {}
);
fs.writeFile(
dir + "/public_key.txt",
publicKey.export({ type: "spki", format: "der" }).toString("base64") +
"\n",
err => {}
);
fs.writeFile(
dir + "/private.pem",
privateKey.export({ type: "pkcs1", format: "pem" }),
err => {}
);
}
);
console.log("Public key saved in " + dir + "/public_key.txt");
Register public key
You will use the Key API to register your public key with Brightcove.
Key API
The Key API is used to manage your public keys with Brightcove.
Base URL
The base URL for the API is:
https://playback-auth.api.brightcove.com
Account path
In all cases, requests will be made for a specific Video Cloud Account. So, you will always add the term accounts followed by your account id to the base URL:
https://playback-auth.api.brightcove.com/v1/accounts/{accountID}
Authorization
An access token for requests is required and must be present in the Authorization header::
Authorization: Bearer {access_token}
The access token is a temporary OAuth2 access token that must be obtained from the Brightcove OAuth service. For details on how to obtain client credentials and use them to retrieve access tokens, see the Brightcove OAuth Overview.
Permissions
Requests to the Key API must be made from client credentials with the following permissions:
-
video-cloud/playback-auth/key/read
-
video-cloud/playback-auth/key/write
Manage keys
The Key API supports the following requests:
Register a new key:
Put the value of your public key in the API request body. You can find the key in the public_key.txt file.
Request
POST /v1/accounts/{accountID}/keys
Content-Type: application/json
Body: {"value": "MFkwEwYHKoZIzj0CAQYIKoZIzj...MyeQviqploA=="}
Using Curl
Response
{
"id": "{your_public_key_id}",
"type": "public",
"algorithm": "rsa",
"value": "{your_public_key_value}",
"createdAt": "2020-01-03T20:30:36.488Z"
}
List keys:
Get a list of public keys in your account.
GET /v1/accounts/{accountID}/keys
Get one key:
Get the details for a public key in your account.
GET /v1/accounts/{accountID}/keys/{key_Id}
Delete one key:
Delete a public key in your account.
DELETE /v1/accounts/{accountID}/keys/{key_Id}
Create a JSON Web Token
Publishers create a JSON Web Token (JWT). The token is signed with the RSA algorithm using the SHA-256 hash algorithm (identified in the JWT spec as "RS256") No other JWT algorithms will be supported.
A subset of the standard JSON Web Token claims will be used, along with some private claims defined by Brightcove. You will create a JSON Web Token signed with your private key.
Claims for Static URL Delivery
The following claims can be used with Brightcove's Static URL Delivery.
Field | Type | Required | Description |
---|---|---|---|
accid |
String | The account id that owns the content being played | |
drules |
String[] | List of delivery rule action IDs to apply, see Implementing Delivery Rules for details. If the config_id query parameter is also set it will be ignored, as this claim overrides it. | |
exp |
Integer | Time this token will no longer be valid, in seconds since the Epoch. Must be no more than 30 days from iat |
|
iat |
Integer | Time this token was issued, in seconds since the Epoch | |
conid |
String | If present, this token will only authorize license fetching for a specific Video Cloud video ID.
Must be a valid video ID. Note that reference ID is not supported. |
|
pro |
String | Specifies a protection type in the case where multiple are available for a single video.
Values:
|
|
vod |
Object | Contains specific configuration options for Video-On-Demand. | |
vod.ssai |
String | Your Server-Side Ad Insertion (SSAI) configuration id. This claim is required to retrieve either an HLS or a DASH VMAP. |
Here is an example of the JSON Web Token (JWT) claims that you might use:
{
// account id: JWT is only valid for this accounts
"accid":"4590388311111",
// drules: list of delivery rule IDs to be applied
"drules": ["0758da1f-e913-4f30-a587-181db8b1e4eb"]
// expires: timestamp when JWT expires
"exp":1577989732,
// issued at: timestamp when the JWT was created
"iat":1575484132,
// content id: JWT is only valid for video ID
"conid":"5805807122222",
// protection: specify a protection type in the case where multiple are available for a single video
"pro":"aes128",
// VOD specific configuration options
"vod":{
// SSAI configuration to apply
"ssai":"efcc566-b44b-5a77-a0e2-d33333333333"
}
}
Generate a token
Libraries are commonly available to generate JWT tokens. For details, see the JSON Web Tokens site.
Example bash script:
Example script to generate the JWT token:
#! /usr/bin/env bash
# Static header fields.
HEADER='{
"type": "JWT",
"alg": "RS256"
}'
payload='{
"accid": "{your_account_id}"
}'
# Use jq to set the dynamic `iat` and `exp`
# fields on the payload using the current time.
# `iat` is set to now, and `exp` is now + 1 second.
PAYLOAD=$(
echo "${payload}" | jq --arg time_str "$(date +%s)" \
'
($time_str | tonumber) as $time_num
| .iat=$time_num
| .exp=($time_num + 60 * 60)
'
)
function b64enc() { openssl enc -base64 -A | tr '+/' '-_' | tr -d '='; }
function rs_sign() { openssl dgst -binary -sha256 -sign playback-auth-keys/private.pem ; }
JWT_HDR_B64="$(echo -n "$HEADER" | b64enc)"
JWT_PAY_B64="$(echo -n "$PAYLOAD" | b64enc)"
UNSIGNED_JWT="$JWT_HDR_B64.$JWT_PAY_B64"
SIGNATURE=$(echo -n "$UNSIGNED_JWT" | rs_sign | b64enc)
echo "$UNSIGNED_JWT.$SIGNATURE"
Run the script:
$ bash jwtgen.sh
Example using Go
Results
Here is an example of a decoded token using https://JWT.io specifying the full set of claims:
HEADER:
{
"alg": "RS256",
"type": "JWT"
}
PAYLOAD:
{
"accid": "1100863500123",
"conid": "51141412620123",
"exp": 1554200832,
"iat": 1554199032,
"maxip": 10,
"maxu": 10,
"ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36"
}
Test playback
Although not required, you may want to test video playback before configuring a player.
Request playback:
curl -X GET \
-H 'Authorization: Bearer {JWT}' \
https://edge-auth.api.brightcove.com/playback/v1/accounts/{your_account_id}/videos/{your_video_id}