Skip to content

DRM and token auth testing

Most commercial streaming platforms protect content with either signed URL tokens, session-bound authentication cookies, or full DRM systems (Widevine, FairPlay, PlayReady). Under load, each of these introduces failure modes that plain unauthenticated tests never reveal: license server saturation, token generation throughput limits, auth middleware latency spikes, and token expiry races. This page explains how to include auth and DRM requests in your MaxoPerf streaming tests.

Signed URLs embed an auth token (HMAC signature, JWT, or CDN-specific token) in the query string of each manifest and segment URL. The CDN or edge validates the token before serving the response.

ComponentFailure mode
Token generation serviceCannot issue enough tokens per second for all concurrent sessions; returns 429 or 503
CDN token validationClock skew or token cache miss causes valid tokens to be rejected; 403 spike
Token expiryShort-lived tokens expire mid-session; later segment requests fail with 403
Shared secret rotationNew tokens use the new secret before CDN edge nodes have fetched it; transient 403

For tokens that are static during a test (pre-issued, long-lived for test purposes), embed the token in the URL directly using a MaxoPerf secret:

scenarios:
signed-url-viewer:
requests:
# Token is embedded in the URL query string
# Use a MaxoPerf secret for the token value
- label: master-manifest
url: "https://cdn.example.com/stream/master.m3u8?token=${CDN_TOKEN}&expires=9999999999"
method: GET
- label: variant-playlist
url: "https://cdn.example.com/stream/720p/playlist.m3u8?token=${CDN_TOKEN}&expires=9999999999"
method: GET
- label: segment
url: "https://cdn.example.com/stream/720p/seg-0001.ts?token=${CDN_TOKEN}&expires=9999999999"
method: GET
- label: segment
url: "https://cdn.example.com/stream/720p/seg-0002.ts?token=${CDN_TOKEN}&expires=9999999999"
method: GET
think-time: 4s

Set CDN_TOKEN in MaxoPerf secrets. This approach tests whether the CDN correctly validates tokens under load but does not test token generation throughput.

If your platform issues a new token per session at session start (a common pattern for short-lived tokens), model the token request at the start of each VU iteration:

scenarios:
session-token-then-stream:
requests:
# Step 1 — get a session token
- label: get-session-token
url: https://auth.example.com/v1/stream-token
method: POST
headers:
Authorization: "Bearer ${API_KEY}"
Content-Type: application/json
body: '{"contentId": "event-2026-final", "userId": "${USER_ID}"}'
extract-jsonpath:
cdn_token: $.token
expires_at: $.expiresAt
# Step 2 — use token for streaming requests
- label: master-manifest
url: "https://cdn.example.com/stream/master.m3u8?token=${cdn_token}"
method: GET
- label: variant-playlist
url: "https://cdn.example.com/stream/720p/playlist.m3u8?token=${cdn_token}"
method: GET
- label: segment
url: "https://cdn.example.com/stream/720p/seg-0001.ts?token=${cdn_token}"
method: GET
- label: segment
url: "https://cdn.example.com/stream/720p/seg-0002.ts?token=${cdn_token}"
method: GET
think-time: 4s

The get-session-token label will appear separately in your MaxoPerf results. You can spot token-service saturation by watching get-session-token p95 latency — rising latency here predicts session start failures under load before the streaming layer is even reached.

To test token expiry behavior, issue a token with a short TTL (e.g., 60 seconds) and model a viewer session longer than that TTL. The later segment requests will fail with 403 — and your test result should show that failure and give you the signal to add token renewal logic to your player or middleware.

scenarios:
short-lived-token-viewer:
requests:
- label: get-short-token
url: https://auth.example.com/v1/stream-token?ttl=60
method: POST
body: '{"contentId": "event-final"}'
extract-jsonpath:
short_token: $.token
- label: master-manifest
url: "https://cdn.example.com/stream/master.m3u8?token=${short_token}"
method: GET
- label: segment
url: "https://cdn.example.com/stream/720p/seg-0001.ts?token=${short_token}"
method: GET
# ... segments continue for 90 seconds total (past the 60s token TTL)
# Segments after 60s should return 403 — confirming token expiry behavior
- label: segment-after-expiry
url: "https://cdn.example.com/stream/720p/seg-0016.ts?token=${short_token}"
method: GET
think-time: 4s

After the run, filter the Log tab in MaxoPerf for 403 responses on segment-after-expiry to confirm that expiry is enforced correctly and at the expected time boundary.

DRM systems (Widevine, FairPlay, PlayReady) require the player to obtain a license before decrypting and playing content. A license request is an HTTP POST to a license server that typically involves:

  1. A license challenge (generated by the player’s CDM) sent as a POST body.
  2. The license server validating the viewer’s entitlement.
  3. A license blob returned and decrypted by the CDM.

License requests happen once at session start (for a playback session) or periodically (for rotating keys). Model them as an additional labeled request at the start of each VU session:

scenarios:
drm-protected-viewer:
requests:
# DRM license acquisition — happens once per session
- label: drm-license-request
url: https://license.example.com/v1/widevine
method: POST
headers:
Authorization: "Bearer ${SESSION_TOKEN}"
Content-Type: application/octet-stream
# Use a pre-captured license challenge blob for load testing
# Real CDM challenge is device-specific; use a test challenge that the license server accepts
body: "${DRM_CHALLENGE_B64_ENCODED}"
assert:
- equals:
subject: http-code
value: '200'
# Session setup: manifest and variant playlist
- label: master-manifest
url: "https://cdn.example.com/stream/master.m3u8?token=${SESSION_TOKEN}"
method: GET
- label: variant-playlist
url: "https://cdn.example.com/stream/720p/playlist.m3u8?token=${SESSION_TOKEN}"
method: GET
# Segment loop
- label: segment
url: "https://cdn.example.com/stream/720p/seg-enc-0001.m4s"
method: GET
- label: segment
url: "https://cdn.example.com/stream/720p/seg-enc-0002.m4s"
method: GET
think-time: 4s

What to watch for in DRM load test results

Section titled “What to watch for in DRM load test results”
LabelSignal
drm-license-request p95 risingLicense server is saturating under concurrent session starts
drm-license-request error rate > 0License server rejecting requests — check entitlement service, quota limits
drm-license-request p95 OK, segment 4xxLicense is granted but CDN key validation is failing — key rotation or token scope issue

At live-event scale, all viewers request a license within the first 60 seconds of kickoff. This creates a license server spike identical in profile to the CDN manifest spike. Size your license server autoscaling to handle the same concurrency as your CDN manifest server.

Do:

  • Test token generation separately from segment delivery — label the token request so you can see its latency independently.
  • Use MaxoPerf secrets for API keys, token signing secrets, and test credentials. Never hard-code them in test files.
  • Simulate token expiry to verify your renewal logic handles it gracefully before real viewers encounter it.

Don’t:

  • Assume DRM license server capacity is free — license servers have CPU-intensive key derivation per request and are frequently the bottleneck at live-event scale.
  • Use production DRM license server credentials in load tests without a strict rate-limit plan and sign-off from your operations team.
  • Forget to test the CDN edge’s token validation behavior — CDN token validation is a separate code path from origin auth, and edge capacity limits can differ significantly.