Protect your content with signed URLs

Prevent unauthorized viewers from downloading your content or embedding your player on sites that you do not own.

Last Updated: October 21, 2019

JW Player enables you to create expiring, signed URLs to secure your content and player. Using signed URLs for your public content or player prevents unauthorized viewers from downloading your content or embedding your player on sites that you do not own.

To enable URL signing on your media content and players, you must complete two general processes:

  1. Create signed (non-JWT or JWT) URLs.
  2. Enable URL signing functionality

Before explaining how to implement URL signing, the next section explains the types of signed URLs that JW Player supports.


Types of signed URLs

JW Player's Delivery API supports two methods of signing URLs:

  • Signed non-JWT (non-JWT)
  • JSON web token (JWT) tokenized

Non-JWT URLs apply when you reference any of JW Player's v1 endpoints and routes. JWT URLs apply when you reference any of the JW Player's v2 endpoints and routes.

The following table identifies when to use each type of signed URL.

Signed URL type Applicable routes
non-JWT Players*
  • /libraries/player_id.js
  • /players/content_id-player_id.embed_type
  • /previews/content_id-player_id.html

Poster image
  • /thumbs/media_id-thumb_width.jpg

Streaming manifests
  • /manifests/media_id.manifest_extension

Text tracks
  • /tracks/track_id.track_extension

Video files
  • /videos/media_id-template_id.media_extension
JWT Advertising schedule*
  • /v2/advertising/schedules/ad_schedule_id.ad_schedule_extension

Media
(This includes streaming manifests, text tracks, and video files)
  • /v2/media/media_id

Playlist
  • /v2/playlists/playlist_id

Poster image
  • /v2/media/media_id/poster.jpg

* Denotes content that can be accessed only through this route of the Delivery API.


Create a signed non-JWT URL

To create a non-JWT URL, you must append two parameters to the URL of the content or player: exp and sig.

http://cdn.jwplayer.com/videos/nPripu9l.mp4?exp=1371335018&sig=a0124258c73177029d09bb82c6608392
Parameter Description
exp Expiration date of the URL as a UNIX timestamp, for example, 1271338236

Typically, generated URLs should be valid between a minute and a few hours.
sig Signature used to authorize the request

See: sig parameter.


sig parameter

The signature (sig) is an MD5 digest of the path, the expiration date, and the account secret: md5(CONTENT_PATH:EXPIRATION_STAMP:ACCOUNT_SECRET).

Parameter Description
ACCOUNT_SECRET Property secret

Use the following steps to locate your property secret:
   1. From your JW Player dashboard, click the gear next to your name > API Credentials.
   2. In the JW Platform API Credentials section, click SHOW CREDENTIALS next to a property name.
   3. Copy the Secret.
CONTENT_PATH Only the path portion of the URL without the domain or leading slash, for example, videos/nPripu9l.mp4
EXPIRATION_STAMP Expiration date of the URL as a UNIX timestamp, for example, 1271338236


Generate the non-JWT signed URL

The following code examples show approaches to programmatically generate a non-JWT signed URL.

IMPORTANT

The following samples are provided for guidance and may not work in your environment. If you use any of these samples, be sure to test the functionality in a development environment before deploying it into a production environment.

<?php
function get_signed_player($videokey,$playerkey) {
  $path = "players/".$videokey."-".$playerkey.".js";
  $expires = round((time()+3600)/300)*300;
  $secret = "Ksi93hsy38sjKfha9JaheEMp";
  $signature = md5($path.':'.$expires.':'.$secret);
  $url = 'http://cdn.jwplayer.com/'.$path.'?exp='.$expires.'&sig='.$signature;
  return $url;
};

echo "<p>Watch this cool video:</p>";
echo "<script type='text/javascript' src='".get_signed_player('nPripu9l','ALJ3XQCI')."'></script>";
?>
import time
import hashlib


def get_signed_player(video_key, player_key):
    path = "players/{video_key}-{player_key}.js".format(
        video_key=video_key, player_key=player_key
    )
    expires = round((time.time() + 3600) / 300) * 300
    secret = "INSERT SECRET HERE"
    signature = hashlib.md5(
        "path:{exp}:{secret}".format(exp=str(expires), secret=secret)
    )
    url = "http://cdn.jwplayer.com/{path}?exp={exp}&sig={sig}".format(
        path=path, exp=str(expires), sig=signature.hexdigest()
    )
    return url


video_key = "nPripu9l"  # example video key
player_key = "ALJ3XQCI"  # example player key
signed_url = get_signed_player(video_key, player_key)
print("<p>Watch this cool video:</p>")
print(
    "<script type='text/javascript' src='{signed_url}'></script>".format(
        signed_url=signed_url
    )
)



Create a signed JWT URL

To create a JWT URL, you must append a token parameter to the URL of the content or player. The token parameter is comprised of three Base64-URL strings separated by dots that can be easily passed in HTML and HTTP environments.

To generate the token parameter you need a header, payload, and signature. The next three subsections define the header, payload, and signature. Then, the Generate the JWT signed URL subsection provides code examples to generate the JWT signed URL.


Header

The header specifies the cryptographic algorithm and token type. JW Player currently supports a single algorithm and token type. All headers should use the following:

{
  "alg": "HS256",
  "typ": "JWT"
}
Property Type Description
alg String (Required) Signing algorithm used

This is always HMAC SHA256 (HS256).
typ String (Required) Type of token

This is always JWT.


Payload

The payload consists of claims that specify a resource (resource) being requested, an expiration time (exp), and any parameters the route accepts. The following code example includes related_media_id as an additional parameter.

The resource and exp properties are required.

{
  "resource": "/v2/playlists/Xw0oaD4q",
  "exp": 1893456000,
  "related_media_id": "RltV8MtT"
}
Property Type Description
exp Number (Required) Expiration date of the token, as a UNIX timestamp

Generated URLs should be valid between a minute and a few hours.

The shorter you make the duration until an expiration date, the more secure you make your content. Once a link has expired, even download tools will not be able to grab the content. However, overly short expirations can result in bad user experience due to small discrepancies in server time or delays in clients requesting resources.

If you have a high-volume website, you should cache signed URLs (for example in intervals of 5 minutes) to prevent performance issues that may occur due to generating signed URLs. Signed requests do not have to be unique.
resource String (Required) Content or player that is being requested

This can be a relative or absolute URL. This property ensures that generated tokens cannot be applied to unintended resources.


Signature

The signature is comprised of the encoded header, the encoded payload, and the property secret.

Use the following steps to locate your property secret:

  1. From your JW Player dashboard, click the gear next to your name > API Credentials.
  2. In the JW Platform API Credentials section, click SHOW CREDENTIALS next to a property name.
    3, Copy the Secret.


Generate the JWT signed URL

The following code examples show approaches to programmatically generate a JWT signed URL.

IMPORTANT:

The following samples are provided for guidance and may not work in your environment. If you use any of these samples, be sure to test the functionality in a development environment before deploying it into a production environment.

<?php
require_once('JWT.php'); // Available from https://github.com/firebase/php-jwt/blob/master/src/JWT.php	
use \Firebase\JWT\JWT;

$playlist_id = "myListID"; // Replace with your playlist ID
$token_secret = "myAPIsecret"; // Replace this value with the API secret for the property

$resource = "/v2/playlists/".$playlist_id;
$exp = ceil((time() + 3600)/180) * 180; // Link is valid for 1hr but normalized to 3 minutes to promote better caching
$token_body = array(
    "resource" => $resource,
    // Other request parameters can be added here if desired.
    "exp" => $exp
);

$jwt = JWT::encode($token_body, $token_secret);

print "<a href=\"https://cdn.jwplayer.com/$resource?token=$jwt\">This is a signed link.</a>";
from jose import jwt
import math
import time


def jwt_sign_url(path, host='http://cdn.jwplayer.com/'):
    secret = '12345'
    exp = math.ceil((time.time() + 3600)/180) * 180 # Link is valid for 1hr but normalized to 3 minutes to promote better caching

    token_body = {
        "resource": path,
        # Other request parameters can be added here if desired.
        "exp": exp
    }

    url = '{host}?sig={signature}'.format(host=host, signature=jwt.encode(token_body, secret, algorithm='HS256'))
    return url



Enable URL signing functionality

After you have created signed URLs for all of your content, you must enable URL signing functionality for your properties.

Property Settings page within the JW Player dashboard.

Property Settings page within the JW Player dashboard.

  1. From the Properties page of your dashboard, click the name or settings icon of the property. The Property Settings page appears.
  2. On the General tab in the URL Signing section, click the toggle to Secure Video URLs or Secure Player Embeds. Depending on your use case, you can also enable both settings at the same time.
  3. Click SAVE.



Error handling

Error code Error message Posible conditions
200 200 Success Content is requested via a signed URL when URL signing is enabled for all publisher content.
403 403 Access forbidden Content is requested via an unsigned URL when URL signing is enabled for all publisher content.

Content is requested via an incorrectly signed URL when URL signing is enabled for all publisher content.



Protect your content with signed URLs


Prevent unauthorized viewers from downloading your content or embedding your player on sites that you do not own.

Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.