Bitmovin Player pre-integrated bundle
To automate embedding Bitmovin Player on your website the methods from Publish tab in Streaming module might not be flexible enough. For that scenarios we prepared a Bitmovin Player pre-integrated bundle in two variants.
The bundle includes Bitmovin Player and Cloud Video Kit integration software. It allows you to stream content created in Cloud Video Kit using one of the best video players on the market. To use the bundle, you need a Cloud Video Kit account and a Player License Key from console. Once the player is created, you can customize it to your needs by following the Player UI customization guide.
Before integration
Before starting the integration, you need the following four elements for initializing player:
key
- your "@CLOUD_VIDEO_KIT_BITMOVIN_PLAYER_KEY" (from Cloud Video Kit)url
- endpoint which returns addresses to manifests and DRM info (from Cloud Video Kit)token
- JWT token, which contains information about thetenantid
andassetid
of the material you want to play in the payload
The token should be generated by your backend application. Token generation is explained in details below in Token section. Token generated on backend protects your signingKey
. This process adds an extra layer of security and makes life harder for anyone who wants to steal your content.
Integration approaches
JavaScript bundle over CDN
Probably the easiest way to start using pre-integrated Bitmovin Player in your app is by adding link to files hosted over Content Delivery Network. Here are the steps to integrate the JavaScript bundle:
- In the head section of the page, attach the bundled JS file:
<script src="https://cdn.jsdelivr.net/npm/@cloud-video-kit/bitmovin-player@1.0.1/dist/browser/secured/min/index.min.js"></script>
and bitmovin player<script src="https://cdn.bitmovin.com/player/web/8/bitmovinplayer.js"></script>
- In a
script
tag, create a new player instance:var player = new bitmovin.player.CvkBitmovinPlayer(document.getElementById("player"), config);
- Initialize player
await player.initialize()
- Call the
sourceConfig
method, with the endpointurl
and the JWTtoken
as the call parameter (read more about token generation and source config)
Example code:
<html>
<head>
<script src="https://cdn.bitmovin.com/player/web/8/bitmovinplayer.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@cloud-video-kit/bitmovin-player@1.0.1/dist/browser/secured/min/index.min.js"></script>
</head>
<body>
<div id="player"></div>
<script>
(async () => {
var playerConfig = {
// get @cloud-video-kit/bitmovin-player key from https://console.videokit.cloud/dashboard/streaming/configuration#licenses
key: "@CLOUD_VIDEO_KIT_BITMOVIN_PLAYER_KEY",
};
var playerInstance = new bitmovin.player.CvkBitmovinPlayer(
document.getElementById("player"),
playerConfig
);
await playerInstance.initialize(bitmovin.player.Player);
// sourceConfig call - with success response the player is ready to play
// get source config url from https://console.videokit.cloud/dashboard/streaming/configuration#integration-parameters
playerInstance
.sourceConfig("SOURCE-COFIG-URL", "JWT-TOKEN")
.then(
function () {
console.log("Successfully loaded source"); // Success!
},
function () {
console.log("Error while loading source"); // Error!
}
);
})();
</script>
</body>
</html>
NPM package
For more advanced integration, we recommend installing via npm. Please follow these steps:
- Install the package by running
npm i @cloud-video-kit/bitmovin-player
- Import
CvkBitmovinPlayer
into your code usingimport { CvkBitmovinPlayer } from "@cloud-video-kit/bitmovin-player";
- Create a new player instance using
const playerInstance = new CvkBitmovinPlayer(containerElement, config);
- Initialize player
await player.initialize()
- Call the
sourceConfig
method and provide the endpoint URL and JWT token as parameters (read more about token generation and source config)
url
- endpoint that returns addresses to manifests and DRM infotoken
- JWT token that contains information about thetenantid
andassetid
of the material you want to play in the payload.
Example code:
import { CvkBitmovinPlayer } from "@cloud-video-kit/bitmovin-player";
import { UIFactory } from "bitmovin-player-ui";
import "bitmovin-player-ui/dist/css/bitmovinplayer-ui.css";
import { Player } from "bitmovin-player";
const playerConfig: PlayerConfig = {
// get your @cloud-video-kit/bitmovin-player key and Bitmovin Analytics License key from https://console.videokit.cloud/dashboard/streaming/configuration#licenses
key: "@CLOUD_VIDEO_KIT_BITMOVIN_PLAYER_KEY",
analytics: { // optional if you want to use Analytics feature
key: "BITMOVIN_ANALYTICS_LICENSE_KEY",
}
};
const playerContainer = document.getElementById('player');
const playerInstance = new CvkBitmovinPlayer(playerContainer, playerConfig);
// Create the UI
UIFactory.buildDefaultUI(playerInstance);
await playerInstance.initialize(Player);
// sourceConfig call - with success response the player is ready to play
// get your source config url from https://console.videokit.cloud/dashboard/streaming/configuration#integration-parameters
playerInstance.sourceConfig('SOURCE-CONFIG-URL', 'JWT-TOKEN')
.then(
() => {
console.log("Successfully loaded source");
},
() => {
console.log("Error while loading source");
}
);
// HTML
<body>
<div id="player"></div>
</body>
SourceConfig method
Description
The sourceConfig method returns the URLs to the Dash and HLS manifests.
In the case of DRM-protected materials, the response will also contain fields pointing the player to the addresses of Playready
/ Widevine
/ Fairplay
license servers.
Method definition
sourceConfig(url: string, token: string, init?: RequestInit): Promise<void>;
Required
url
- The endpoint that returns addresses to manifests and DRM info. Parameter examplehttps://tenant.streaming.videokit.cloud/v1/sourceconfig
.token
- A JWT token that contains information about thetenantid
,userid
andassetid
of the material you want to play in the payload. For more information about tokens, visit https://jwt.io/introduction
Optional
init
- Contains network request properties used to modify an HTTP request. For more information, visit RequestInit
Token generation
Instead of passing the tenantID, assetID, and userID directly as parameters for the method, the API expects a token. This mechanism adds an extra layer of security as the tokens are signed using a secretKey
. Token generation should occur on the backend to secure the secretKey from being exposed.
Token access protection can be disabled per tenant or per asset. It will make your integration easier, but your content will be less secure.
In our case, the token in the payload section contains the following information:
tenantid
=[string] - Thetenantid
in Cloud Video Kit is a unique string that identifies your account.assetid
=[string] - The ID of the material you want to open in the player. It's a unique identifier of an asset created in VOD, Recorder or Live module. You can find it in the table of contents, or on asset’s detail page in Cloud Video Kit web consoleuserid
=[string] -userid
of the end user who wants to play the material. This parameter is optional and is used for limitting concurrent sessions per userexp
=[number] - Expiration time of the JWT token, in the form of a Unix timestamp. We recommend keeping it short-lived, for example, 60 seconds.
Example token payload:
{
"tenantid": "fed119a4-6bad-49c4-a53a-25a4c1a0b49c",
"assetid": "b95005b5-a6aa-4ccf-a850-b745ff1c1513",
"userid": "user123",
"exp": 1676981532
}
"5EEwZcVIlDTTmg2yUl56g+8lUE/yyah1XrJrUQBWpbU=" is a secretKey
used in below examples. Your value of this parameter will be provided by Insys.
Examples
Below, you will find sample token generation code for various programming languages.
- C#
- Java
- Node.js
- Python
- PHP
- Ruby
- Go
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
namespace dotnet
{
internal static class JwtToken
{
private static readonly string Key = "5EEwZcVIlDTTmg2yUl56g+8lUE/yyah1XrJrUQBWpbU=";
public static string CreateToken()
{
var expiration = DateTime.Now.AddSeconds(60);
JwtPayload payload = new JwtPayload(null, null, new List<Claim>(), null, expiration);
payload.Add("tenantid", "fed119a4-6bad-49c4-a53a-25a4c1a0b49c");
payload.Add("assetid", "b95005b5-a6aa-4ccf-a850-b745ff1c1513");
payload.Add("userid", "user123");
var keyBytes = Convert.FromBase64String(Key);
var signingKey = new SymmetricSecurityKey(keyBytes);
SigningCredentials signing = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
JwtHeader header = new JwtHeader(signing);
JwtSecurityToken token = new JwtSecurityToken(header, payload);
var handler = new JwtSecurityTokenHandler();
var tokenString = handler.WriteToken(token);
return tokenString;
}
public static bool ValidateToken(string token)
{
var keyBytes = Convert.FromBase64String(Key);
var signingKey = new SymmetricSecurityKey(keyBytes);
var tokenHandler = new JwtSecurityTokenHandler();
try
{
tokenHandler.ValidateToken(
token,
new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingKey,
ValidateAudience = false,
ValidateIssuer = false,
ValidAlgorithms = new List<string> { SecurityAlgorithms.HmacSha256 },
RequireExpirationTime = true,
RequireSignedTokens = true,
ValidateLifetime = true,
},
out SecurityToken validatedToken);
}
catch
{
return false;
}
return true;
}
}
}
import java.security.Key;
import java.sql.Date;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Base64;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
public class JwtToken {
private static String Key = "5EEwZcVIlDTTmg2yUl56g+8lUE/yyah1XrJrUQBWpbU=";
public static String CreateToken() {
byte[] keyBytes = Base64.getDecoder().decode(Key);
Key hmac = Keys.hmacShaKeyFor(keyBytes);
Instant now = Instant.now();
String jwtToken = Jwts.builder()
.setHeaderParam("alg", "HS256")
.setHeaderParam("type", "JWT")
.claim("tenantid", "fed119a4-6bad-49c4-a53a-25a4c1a0b49c")
.claim("assetid", "b95005b5-a6aa-4ccf-a850-b745ff1c1513")
.claim("userid", "user123")
.setExpiration(Date.from(now.plus(5l, ChronoUnit.MINUTES)))
.signWith(hmac)
.compact();
return jwtToken;
}
public static Jws<Claims> ValidateToken(String jwtString) {
try {
byte[] keyBytes = Base64.getDecoder().decode(Key);
Key hmac = Keys.hmacShaKeyFor(keyBytes);
Jws<Claims> jwt = Jwts.parserBuilder()
.setSigningKey(hmac)
.build()
.parseClaimsJws(jwtString);
System.out.println("Token is valid");
return jwt;
} catch (Exception e) {
System.out.println("Token is invalid");
return null;
}
}
}
var jwt = require("jsonwebtoken");
const base64_signingkey = '5EEwZcVIlDTTmg2yUl56g+8lUE/yyah1XrJrUQBWpbU=';
const payload = {
"exp": 1701785104,
"tenantid": "fed119a4-6bad-49c4-a53a-25a4c1a0b49c",
"assetid": "b95005b5-a6aa-4ccf-a850-b745ff1c1513",
"userid": "user123"
}
const create_token = () => {
const token = jwt.sign(payload, Buffer.from(base64_signingkey, "base64"), {
algorithm: "HS256",
});
return token;
};
const decode_token = (token) => {
const decoded = Buffer.from(base64_signingkey, "base64");
const verify = jwt.verify(token, decoded);
console.log(verify ? "Token is valid" : "Token invalid");
};
const token = create_token()
console.log(token);
decode_token(token);
from packages import jwt
import base64
base64_signingkey = '5EEwZcVIlDTTmg2yUl56g+8lUE/yyah1XrJrUQBWpbU='
payload = {
"exp": 1701785104,
"tenantid": "fed119a4-6bad-49c4-a53a-25a4c1a0b49c",
"assetid": "b95005b5-a6aa-4ccf-a850-b745ff1c1513",
"userid": "user123"
}
def create_token(key):
secret = base64.b64decode(key)
encoded_jwt = jwt.encode(payload, secret, algorithm='HS256')
print(encoded_jwt)
return encoded_jwt
def decode_token(key, token):
secret = base64.b64decode(key)
payload = jwt.decode(token, secret, algorithms=['HS256'])
print(payload)
if __name__ == "__main__":
token = create_token(base64_signingkey)
decode_token(base64_signingkey, token) # If invalid set exp time from future
<?php
require __DIR__ . '/vendor/autoload.php';
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
$key = "5EEwZcVIlDTTmg2yUl56g+8lUE/yyah1XrJrUQBWpbU=";
$date = new DateTimeImmutable();
$expire_at = $date->modify('+6 minutes')->getTimestamp(); // Add 60 seconds
$payload = [
'tenantid' => "fed119a4-6bad-49c4-a53a-25a4c1a0b49c",
'assetid' => "b95005b5-a6aa-4ccf-a850-b745ff1c1513",
'userid' => "user123",
'exp' => $expire_at,
];
$jwt = JWT::encode($payload, base64_decode($key), 'HS256');
print_r($jwt . "\n");
$decoded = JWT::decode($jwt, new Key(base64_decode($key), 'HS256'));
print_r($decoded);
require 'JWT'
require 'base64'
class JsonWebToken
SECRET_KEY = "5EEwZcVIlDTTmg2yUl56g+8lUE/yyah1XrJrUQBWpbU="
def encode()
payload = {}
payload[:tenantid] = "fed119a4-6bad-49c4-a53a-25a4c1a0b49c"
payload[:assetid] = "b95005b5-a6aa-4ccf-a850-b745ff1c1513"
payload[:userid] = "user123"
payload[:exp] = (Time.now + 600).to_i
return JWT.encode(payload, Base64.decode64(SECRET_KEY))
end
def decode(token)
begin
decoded = JWT.decode(token, Base64.decode64(SECRET_KEY))[0]
puts "Token is valid"
rescue Exception => e
puts "Token is invalid"
end
end
end
instance = JsonWebToken. new
token = instance.encode()
puts token
instance.decode(token)
package main
import (
"encoding/base64"
"fmt"
"time"
"github.com/golang-jwt/jwt"
)
var Key = "5EEwZcVIlDTTmg2yUl56g+8lUE/yyah1XrJrUQBWpbU="
func main() {
token, _ := createToken()
fmt.Println(token)
validateToken(token)
}
func createToken() (string, error) {
token := jwt.New(jwt.SigningMethodHS256)
claims := token.Claims.(jwt.MapClaims)
claims["tenantid"] = "fed119a4-6bad-49c4-a53a-25a4c1a0b49c"
claims["assetid"] = "b95005b5-a6aa-4ccf-a850-b745ff1c1513"
claims["userid"] = "user123"
claims["exp"] = time.Now().Add(time.Minute * 1).Unix()
keyBytes, _ := base64.StdEncoding.DecodeString(Key)
tokenString, err := token.SignedString(keyBytes)
if err != nil {
fmt.Errorf("Something Went Wrong: %s", err.Error())
return "", err
}
return tokenString, nil
}
func validateToken(tokenval string) (err error) {
token, err := jwt.Parse(tokenval, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("There was an error in parsing")
}
keyBytes, _ := base64.StdEncoding.DecodeString(Key)
return keyBytes, nil
})
if token != nil {
fmt.Println("token valid")
}
return nil
}