How to Secure Video Content With Signed Keys

Signed Keys let you control who can watch your embedded videos and live streams, and for how long. Instead of a static embed code that anyone can copy, Signed Keys generate a time-limited token on your server — so even if someone grabs your embed URL, it expires in minutes.

Works with both VOD and Live streams. The token generation process is identical — only the Content ID format and embed URL path differ.

This guide walks you through everything you need to get Signed Keys working on your website.


How It Works

  1. A visitor opens a page on your website.
  2. Your backend server generates a short-lived token using your secret signing key.
  3. The token is appended to the Dacast embed URL (?signedKey=...).
  4. Dacast verifies the token. If it’s valid and not expired, the video plays.
Visitor → Your Server (generates token) → Dacast Player (verifies token) → Video plays

Important: Token generation must happen on your server (backend). Never expose your signing key in client-side code.


What You Need

ItemWhere to find it
Signing KeyDacast dashboard → Settings → Security → Signed Keys
Content IDDacast dashboard → Video / Stream details. Format: <accountId>-vod-<videoId> or <accountId>-live-<streamId>
A backend serverAny language: Node.js, Python, PHP, Ruby, etc.

Step 1: Get Your Signing Key

  1. Log in to your Dacast dashboard.
  2. Navigate to Settings → Security → Signed Keys.
  3. Copy your signing key. It looks like this: c5057fde-4805-4859-86a2-a88157c3a551.
  4. Store it securely on your server (e.g., in an environment variable).
# .env file on your server
SIGNING_KEY=c5057fde-4805-4859-86a2-a88157c3a551

Never put your signing key in HTML, JavaScript, or any client-facing code.


Step 2: Generate a Signed Token (Backend)

The token has three parts: 2.<expiryTimestamp>.<signature>

PartDescription
2.Fixed prefix — indicates a video-specific token
expiryTimestampUTC time when the token expires, formatted as YYYYMMDDHHMMSS
signatureMD5 hash of <contentId>:<signingKey>:<expiryTimestamp>

Node.js Example

const crypto = require('crypto');

function generateSignedToken(contentId, signingKey, expiryMinutes = 2) {
  // 1. Calculate expiry time in UTC
  const expiryTime = new Date(Date.now() + expiryMinutes * 60 * 1000);

  // 2. Format as YYYYMMDDHHMMSS
  const expiryTimestamp = expiryTime.toISOString()
    .replace(/[-:T]/g, '')
    .replace(/.d{3}Z$/, '');

  // 3. Compute MD5 signature
  const hashInput = `${contentId}:${signingKey}:${expiryTimestamp}`;
  const signature = crypto.createHash('md5').update(hashInput).digest('hex');

  // 4. Assemble token
  return `2.${expiryTimestamp}.${signature}`;
}

// Usage
const token = generateSignedToken(
  '8f2facdc-1a29-5903-bffb-8414b3ee5da5-vod-33ce2526-0e2f-44f4-8693-fa8c66ec78f6',
  process.env.SIGNING_KEY
);
console.log(token);
// → 2.20260129143000.a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4

Python Example

import hashlib
from datetime import datetime, timedelta, timezone

def generate_signed_token(content_id: str, signing_key: str, expiry_minutes: int = 2) -> str:
    # 1. Calculate expiry time in UTC
    expiry_time = datetime.now(timezone.utc) + timedelta(minutes=expiry_minutes)

    # 2. Format as YYYYMMDDHHMMSS
    expiry_timestamp = expiry_time.strftime('%Y%m%d%H%M%S')

    # 3. Compute MD5 signature
    hash_input = f'{content_id}:{signing_key}:{expiry_timestamp}'
    signature = hashlib.md5(hash_input.encode()).hexdigest()

    # 4. Assemble token
    return f'2.{expiry_timestamp}.{signature}'

# Usage
token = generate_signed_token(
  '8f2facdc-1a29-5903-bffb-8414b3ee5da5-vod-33ce2526-0e2f-44f4-8693-fa8c66ec78f6',
  os.environ['SIGNING_KEY']
)

PHP Example

function generateSignedToken(string $contentId, string $signingKey, int $expiryMinutes = 2): string {
    // 1. Calculate expiry time in UTC
    $expiryTime = gmdate('YmdHis', time() + $expiryMinutes * 60);

    // 2. Compute MD5 signature
    $hashInput = "{$contentId}:{$signingKey}:{$expiryTime}";
    $signature = md5($hashInput);

    // 3. Assemble token
    return "2.{$expiryTime}.{$signature}";
}

// Usage
$token = generateSignedToken(
  '8f2facdc-1a29-5903-bffb-8414b3ee5da5-vod-33ce2526-0e2f-44f4-8693-fa8c66ec78f6',
  getenv('SIGNING_KEY')
);

Step 3: Add the Token to Your Embed Code

Dacast supports two embed methods. Add the token as a signedKey parameter to either one.

Both methods work identically for VOD and Live content — you just use the appropriate Content ID.

Option A: JavaScript (Script) Embed

Pass the full Content ID (VOD or Live) as contentId:

<div style="min-height:500px; min-width:480px; width:100%; position:relative; aspect-ratio:1.78;">
  <script
    id="YOUR_CONTENT_ID"
    style="position:absolute; top:0; left:0; width:100%; height:100%;"
    class="iframe-player-dacast" data-src="https://player.dacast.com/js/player.js?contentId=YOUR_CONTENT_ID&provider=singularity&signedKey=YOUR_TOKEN"
    class="dc-video">
  </script>
</div>

Option B: Iframe Embed

The iframe URL includes the content type (vod or live) as a path segment:

VOD:  https://iframe.dacast.com/vod/<accountId>/<videoId>?signedKey=YOUR_TOKEN
Live: https://iframe.dacast.com/live/<accountId>/<streamId>?signedKey=YOUR_TOKEN

VOD example:

<div style="position:relative; padding-bottom:56.25%; overflow:hidden; height:0; max-width:100%;">
  <iframe
    class="iframe-class" data-src="https://iframe.dacast.com/vod/8f2facdc-1a29-5903-bffb-8414b3ee5da5/33ce2526-0e2f-44f4-8693-fa8c66ec78f6?signedKey=YOUR_TOKEN"
    width="100%" height="100%"
    frameborder="0" scrolling="no"
    allow="autoplay; encrypted-media"
    allowfullscreen
    style="position:absolute; top:0; left:0;">
  </iframe>
</div>

Live stream example:

<div style="position:relative; padding-bottom:56.25%; overflow:hidden; height:0; max-width:100%;">
  <iframe
    class="iframe-class" data-src="https://iframe.dacast.com/live/8f2facdc-1a29-5903-bffb-8414b3ee5da5/520a76a2-17c8-4d75-aac6-67b2bceb1eef?signedKey=YOUR_TOKEN"
    width="100%" height="100%"
    frameborder="0" scrolling="no"
    allow="autoplay; encrypted-media"
    allowfullscreen
    style="position:absolute; top:0; left:0;">
  </iframe>
</div>

Note: For the iframe embed, the Content ID is split into three URL segments: the content type (vod or live), the account ID, and the media ID. For example, accountId-vod-videoId becomes /vod/accountId/videoId.


Step 4: Putting It All Together

Here’s a complete Node.js/Express example that serves a page with a signed video embed:

const express = require('express');
const crypto = require('crypto');
const app = express();

const SIGNING_KEY = process.env.SIGNING_KEY;

function generateSignedToken(contentId, expiryMinutes = 2) {
  const expiryTime = new Date(Date.now() + expiryMinutes * 60 * 1000);
  const expiryTimestamp = expiryTime.toISOString()
    .replace(/[-:T]/g, '')
    .replace(/.d{3}Z$/, '');

  const hashInput = `${contentId}:${SIGNING_KEY}:${expiryTimestamp}`;
  const signature = crypto.createHash('md5').update(hashInput).digest('hex');

  return `2.${expiryTimestamp}.${signature}`;
}

app.get('/video', (req, res) => {
  const contentId = '8f2facdc-1a29-5903-bffb-8414b3ee5da5-vod-33ce2526-0e2f-44f4-8693-fa8c66ec78f6';
  const token = generateSignedToken(contentId);

  res.send(`
    <!DOCTYPE html>
    <html>
    <head><title>My Protected Video</title></head>
    <body>
      <div style="max-width:800px; margin:40px auto;">
        <h1>My Video</h1>
        <div style="position:relative; padding-bottom:56.25%; height:0;">
          <iframe
            class="iframe-class" data-src="https://iframe.dacast.com/vod/8f2facdc-1a29-5903-bffb-8414b3ee5da5/33ce2526-0e2f-44f4-8693-fa8c66ec78f6?signedKey=${token}"
            width="100%" height="100%"
            frameborder="0" scrolling="no"
            allow="autoplay; encrypted-media"
            allowfullscreen
            style="position:absolute; top:0; left:0;">
          </iframe>
        </div>
      </div>
    </body>
    </html>
  `);
});

app.listen(3000, () => console.log('Server running on http://localhost:3000'));

Every time a visitor loads /video, the server generates a fresh token that expires in 2 minutes — long enough to start playback, short enough to prevent link sharing.


FAQ

How long should the token be valid?

2–5 minutes is recommended. The token only needs to be valid when the player initializes. Once playback starts, it continues even after the token expires.

Can I use the same token for multiple videos?

No. Each token is bound to a specific Content ID. You need to generate a separate token for each video.

What happens if the token is expired or invalid?

The Dacast backend will return a 403 Forbidden error and the video will not play.

Do I need to change my embed code every time?

No. Your backend generates a fresh token on each page load. The embed code template stays the same — only the signedKey value changes.

Does this work with live streams?

Yes. The token generation is exactly the same — use the full live Content ID (e.g., accountId-live-streamId) as input. For the iframe embed, replace /vod/ with /live/ in the URL. The JS (script) embed handles this automatically based on the Content ID.


Quick Reference

ParameterValue
VOD Content ID<accountId>-vod-<videoId>
Live Content ID<accountId>-live-<streamId>
Token format2.<YYYYMMDDHHMMSS>.<md5_hex>
MD5 input<contentId>:<signingKey>:<expiryTimestamp>
TimestampUTC, format YYYYMMDDHHMMSS
JS embed param&signedKey=<token>
Iframe VOD URLhttps://iframe.dacast.com/vod/<accountId>/<videoId>?signedKey=<token>
Iframe Live URLhttps://iframe.dacast.com/live/<accountId>/<streamId>?signedKey=<token>
Recommended expiry2–5 minutes
Juan M. Vazquez

Product Manager @ Dacast with a strong focus on building user-centered digital products that drive measurable business impact.