# Guide to Enabling Authentication for ClearKey-Encrypted Videos
Protecting video content from unauthorized access is critically important, especially for streaming providers who need to preserve content value and prevent piracy.
ClearKey is a DRM system that is less complex than Widevine or FairPlay, yet still provides adequate basic protection.
This document describes the weaknesses of the existing ClearKey system and the approach to adding an authentication mechanism to strengthen overall security.
# Overview of the Existing ClearKey System
# Basic Operating Principles
ByteArk Stream supports processing ClearKey-encrypted videos using the AES-128 algorithm for HLS (HTTP Live Streaming) format videos. Viewers cannot watch encrypted videos without first obtaining the encryption key for decryption, even if they manage to download the video by any means.
# HLS Structure and Encryption
In the HLS format, video is divided into smaller pieces called "Segments," and the Manifest file contains references to the location of the decryption key.
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXT-X-KEY:METHOD=AES-128,URI="https://key-server.example.com/key",IV=0x...
#EXTINF:10.0,
segment1.ts
#EXTINF:10.0,
segment2.ts
2
3
4
5
6
7
8
In the example above, #EXT-X-KEY indicates that the video is encrypted with AES-128 and the key can be requested from the specified URL.
# Weaknesses of the Current System
# Lack of Authentication Mechanism
Although the ClearKey system provides basic protection through encryption, it has a critical weakness: key requests have no access control verification.
# Issues
- Unauthorized key access - Malicious actors can directly request the decryption key if they know the URL.
- Key sharing - Authorized users can share the key with others.
- Lack of access control - It is not possible to restrict access by duration, number of uses, or revoke access.
# Sequence Diagram: Legacy System
# ClearKey Legacy System Workflow
# Legacy System Workflow Explanation
# Step 1: Manifest Fetch
The viewer requests the Manifest file from the Manifest Server to receive information about the video they want to watch.
# Step 2: Key Fetch (Main Weakness)
This is the critical weakness of the system. The key is sent immediately without verifying whether the requester is an authorized user.
# Step 3: Video Playback
After receiving the key, the viewer can decrypt and play the video immediately.
# Sequence Diagram: New System with Authentication
# Approach to Fixing the Weaknesses
To address the weaknesses described above, ByteArk has developed a new system that adds an authentication mechanism to the core process, based on the following key principles:
- Key Pair Generation: Create a public/private key pair for digital signing.
- Authentication: Verify user permissions before granting access to content.
- Session Management: Control access duration and scope.
- Domain Verification: Restrict access to authorized sources only.
# New System Sequence Diagram
# New System Workflow Explanation
# Step 1: Setup Key Pair
In this step, the customer creates a Key Pair for authentication:
- Send a request to create a Key Pair to the Stream API along with a PAT and Playback Channel ID.
- Receive the Private Key and Keypair ID in return.
- Store the Private Key securely for signing JWT Tokens.
# Step 2: Authentication
This step is the core of the new system, verifying user permissions before granting access to content:
- The viewer sends an authentication request to the customer's Backend (using OAuth, Username/Password, or other methods as defined by the customer).
- The Backend verifies the user information and creates a JWT Token signed with the Private Key.
- The viewer sends the JWT Token to the Key Server via the SDK using the
initAuth()function. - If valid, the viewer receives a Session and Refresh Token.
# Step 3: Manifest Fetch
After successful authentication, the viewer can request video information:
- Request the Playlist file from the Manifest Server.
- Receive the Playlist back with the Key Server URL.
- Request prog_index.m3u8 specifying
x_ark_origin(or using the default value).
# Step 4: Key Fetch
In the final step, the viewer can request the decryption key:
- Send a request to the Key Server with the attached Session.
- Receive the decryption key in return.
- When the Session is about to expire, call
renewSession()to renew it.
# Passport Key Server APIs
# Authentication and Authorization
All endpoints require the following Request Headers:
| Header | Value | Required | Description |
|---|---|---|---|
Authorization | Bearer <access_token> | Yes | Access token of the authenticated user |
x-byteark-team | <team_identifier> | Yes | Team identifier of the caller |
# 1. Create Key Pair for Playback Channel
Create an ECDSA key pair for a Playback Channel to use for authentication.
# Endpoint
POST /playback-channels/:playbackChannelId/key-pair
# Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
passportKeyServerId | string | Yes | Passport Key Server ID |
# Request Body
Content-Type: application/json
| Field | Type | Required | Description |
|---|---|---|---|
enabledCookieAuth | boolean | Yes | Enable (true) or disable (false) Cookie Authentication |
# Example
{
"enabledCookieAuth": true
}
2
3
# Response
# 200 OK
| Field | Type | Description |
|---|---|---|
id | string | Record ID |
playbackChannelId | string | Playback Channel ID |
allowDomains | string[] | List of allowed domains |
defaultDomain | string | Default domain |
passportClearKeyServerId | string | Passport Clear Key Server ID |
enabledCookieAuth | boolean | Current Cookie Authentication status |
# Example
{
"id": "65a1b2c3d4e5f67890abcdef",
"playbackChannelId": "pc-abc123",
"allowDomains": ["example.com", "cdn.example.com"],
"defaultDomain": "example.com",
"passportClearKeyServerId": "pcks-def456",
"enabledCookieAuth": true
}
2
3
4
5
6
7
8
# 3. Update Allowed Domains
Update the list of allowed domains for the specified Passport Key Server.
# Endpoint
PUT /passport-keyservers/:passportKeyServerId/allow-domains
# Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
passportKeyServerId | string | Yes | Passport Key Server ID |
# Request Body
Content-Type: application/json
| Field | Type | Required | Description |
|---|---|---|---|
allowDomains | string[] | Yes | List of allowed domains |
# Example
{
"allowDomains": ["example.com", "cdn.example.com"]
}
2
3
# Response
# 200 OK
| Field | Type | Description |
|---|---|---|
id | string | Record ID |
defaultDomain | string | Default domain |
allowDomains | string[] | List of allowed domains (updated) |
enabledCookieAuth | boolean | Current Cookie Authentication status |
# Example
{
"id": "65a1b2c3d4e5f67890abcdef",
"defaultDomain": "example.com",
"allowDomains": ["example.com", "cdn.example.com"],
"enabledCookieAuth": true
}
2
3
4
5
6
# 4. Revoke/Unrevoke Key Pair
Revoke or restore the usage of a Key Pair on the Passport Key Server.
# Endpoint
PUT /passport-keyservers/key-pairs/:keyPairId/revoked
# Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
keyPairId | string | Yes | Key Pair ID |
# Request Body
Content-Type: application/json
| Field | Type | Required | Description |
|---|---|---|---|
revoked | boolean | Yes | Revoke (true) or unrevoke (false) the Key Pair |
# Example
{
"revoked": true
}
2
3
# Response
# 200 OK
| Field | Type | Description |
|---|---|---|
keyPairId | string | Key Pair ID |
revoked | boolean | Current revocation status |
# Example
{
"keyPairId": "65a1b2c3d4e5f67890abcdef",
"revoked": true
}
2
3
4
# 404 Not Found
Returned when the specified Key Pair is not found.
| Field | Type | Description |
|---|---|---|
message | string | Error message |
# Domain Configuration Requirements for API Sessions
[!IMPORTANT] To use API Sessions (Cookie-based Authentication), the Key Server domain and the Client domain must be under the same Top-Level Domain.
# Why Domain Configuration Must Match
The session system uses an HTTP Cookie (session_token) to store the token. The cookie domain is set to the root domain of the Key Server, for example:
| Key Server Hostname | Cookie Domain Set |
|---|---|
api.example.com | .example.com |
key-server.byteark.com | .byteark.com |
localhost | localhost |
Since browsers only send cookies back to servers with matching domains, if the Client is on a different Top-Level Domain from the Key Server, the cookie will not be sent, rendering the session unusable.
# Examples
# Works (Matching Domains)
Key Server: https://api.example.com
Client App: https://player.example.com
→ Cookie Domain = .example.com → Shared successfully
2
3
# Does Not Work (Mismatched Domains)
Key Server: https://api.example.com
Client App: https://player.another-site.com
→ Cookie Domain = .example.com → Browser does not send cookie to another-site.com
2
3
# Solution
If the Client domain does not match the Key Server, create an Alias (CNAME) for the Key Server domain under the same domain as the Client, for example:
Client App: https://player.mysite.com
Key Server: https://api.example.com
→ Create CNAME: key-server.mysite.com → api.example.com
→ Call API via: https://key-server.mysite.com
→ Cookie Domain = .mysite.com → Shared successfully
2
3
4
5
6
[!WARNING] If you do not create a domain alias, the session system will not work because the browser will not send cookies across domains, and all API calls requiring a session will receive HTTP 401 Unauthorized every time.
# Summary
| Action Required | Details |
|---|---|
| Verify domains | Ensure the Client and Key Server are under the same Top-Level Domain |
| Create CNAME (if needed) | Alias the Key Server domain under the Client's domain |
| Configure SSL | Ensure the aliased domain has a valid SSL Certificate |
| Test cookies | Verify that the session_token cookie is sent correctly with requests |