Skip to content

DRM and token auth testing

Most commercial streaming platforms protect content with signed URL tokens, session-bound authentication cookies, or full DRM systems (Widevine, FairPlay, PlayReady). Under load, each of these adds failure modes that plain unauthenticated tests never show: license server saturation, token generation throughput limits, auth middleware latency spikes and token expiry races. This page shows how to add auth and DRM requests to 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

If the token stays the same for the whole test (pre-issued, long-lived for test purposes), put it straight into the URL with 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 checks that the CDN validates tokens correctly under load. It does not test token generation throughput.

If your platform issues a new token for each session at session start (common 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 shows up on its own in your MaxoPerf results. Watch get-session-token p95 latency to spot token-service saturation. Rising latency here predicts session start failures under load, before any request reaches the streaming layer.

To test token expiry, issue a token with a short TTL (e.g., 60 seconds) and model a viewer session longer than that TTL. The later segment requests fail with a 403 response. Your test result should show that failure, which tells you 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. This confirms that expiry is enforced, and at the expected time.

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 extra 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 the entitlement service and quota limits
drm-license-request p95 OK, segment 4xxLicense is granted but CDN key validation is failing: a key rotation or token scope issue

At live-event scale, all viewers request a license within the first 60 seconds of kickoff. The license server spike has the same profile as the CDN manifest spike. Size your license server autoscaling for 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 on its own.
  • Use MaxoPerf secrets for API keys, token signing secrets, and test credentials. Never hard-code them in test files.
  • Simulate token expiry to check that your renewal logic handles it before real viewers run into it.

Don’t:

  • Assume DRM license server capacity is free. License servers do CPU-intensive key derivation on every request and are often 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 token validation at the CDN edge. It runs on a separate code path from origin auth, and edge capacity limits can differ a lot.