Encrypted Streaming
Protected playback in Vylux currently uses:
- HLS + CMAF
- raw-key encryption
cbcsprotection scheme- playlist references through
#EXT-X-KEY
Where encryption is enabled
Encryption currently appears in:
video:transcodewhenoptions.encrypt=truevideo:fullwhenoptions.transcode.encrypt=true
If encrypt is false, the HLS pipeline still runs normally but does not emit encryption metadata or require /api/key/{hash}.
Key-material lifecycle
What is actually stored in the database
Vylux does not persist plaintext content keys. It stores:
wrapped_keywrap_noncekek_versionkidschemekey_uri
In other words, PostgreSQL holds unwrap metadata, not player-ready secret material.
The raw AES content key is also not written to a temporary key file. The worker passes key material directly to Shaka Packager through raw-key CLI arguments, so the deployment no longer needs a separate tmpfs mount just to protect encryption keys on disk.
The role of BASE_URL
When the worker enables encryption, it constructs:
{BASE_URL}/api/key/{hash}
as the key_uri written into the playlist.
Therefore:
BASE_URLmust point to the public Vylux hostname that players can reachBASE_URLmust not have a trailing slash- if
BASE_URLis wrong, the playlist may still be generated but playback key fetches will fail
Key endpoint semantics
The player requests /api/key/{hash} when playback reaches encrypted content.
- missing Bearer token:
401 Unauthorized - invalid or expired token:
403 Forbidden - missing key row for the hash:
404 Not Found - valid token:
200 OKwith the 16-byte content key
Additionally:
- successful responses include
Cache-Control: no-store - the response type is
application/octet-stream - this endpoint does not accept
X-API-Key; it only accepts Bearer tokens
There is also a Redis-backed rate limit on the key endpoint.
Bearer token model
The token payload must at least include:
hashexp
The key handler validates:
- token format
- the HMAC-SHA256 signature
- expiration
- hash equality between the token payload and the request path
Integration model
Vylux does not mint playback tokens on its own. Your upstream application is expected to decide who can watch protected media and provide the Bearer token required by the key endpoint.
Testing expectations
Before validating successful key delivery, obtain a valid Bearer token for the same media hash through your upstream application or a test helper.
At minimum, encrypted-streaming validation should confirm:
results.streaming.encrypted == true- the playlist contains
#EXT-X-KEY /api/key/{hash}returns401without a token/api/key/{hash}returns403for an invalid, expired, or mismatched token/api/key/{hash}returns404if no key row exists for the hash- a valid token returns exactly 16 bytes
Player integration
If you use hls.js, only attach the Authorization header to /api/key/ requests. Do not put the token in the query string.
xhrSetup: (xhr, url) => {
if (url.includes('/api/key/') && keyToken) {
xhr.setRequestHeader('Authorization', `Bearer ${keyToken}`);
}
}
Why raw-key plus a key API
This design is not full DRM. Its purpose is to separate key delivery from media distribution:
- playlists and segments can be cached aggressively by a CDN
- keys stay behind an authenticated API boundary
- the upstream application remains in charge of token issuance and lifetime
That is a practical model for protected media without requiring a full DRM platform.