Build a DRM Token Vending System for Premium Video


security api-design reliability

System Design Deep Dive

DRM Token Vending System

40 million subscribers, one licensed stream each, revoked in seconds not hours.

⏱ 16 min read 📐 Advanced 🔒 Security

Picture a concert venue that sells tiered wristbands at the door. The wristband proves you paid, but security still scans it at every gate you pass through on your way to your seat, the bar, and back. If the box office issues a refund on your ticket mid-show, the very next gate you approach turns you away, even though the physical wristband on your arm looks completely unchanged. The wristband itself never had to be clawed back. The gates simply stopped honoring it.

A DRM token vending system is that gate-scanning layer for premium video. Every time a subscriber presses play, the system has to answer “is this specific person, on this specific device, still allowed to watch this specific piece of content, right now” and it has to keep answering that question for every segment of a two-hour movie, not just once at the start. At 40 million subscribers and 3 million concurrent streams during a peak event, that question gets asked roughly half a million times a second, and the answer has to be correct within seconds of a subscription lapsing, a password being shared, or an account being flagged for abuse.

The naive approach is to issue one long-lived DRM license per login and trust it for the rest of the session. That collapses under three forces. First, a license valid for hours means a canceled subscription, a fraud flag, or a stolen credential stays exploitable for however long that license has left to run, which is a standing security liability nobody wants to own. Second, checking entitlement against a central database on every single video segment request, at half a million requests a second, would either fall over or force you to run an origin database cluster sized for load that has nothing to do with your actual write volume. Third, DRM systems like Widevine and FairPlay control the content-key handshake inside the player’s secure media pipeline, which the CDN edge serving video segments cannot see or participate in, so the CDN needs its own independent, fast way to decide yes or no on every segment fetch.

The forces in tension are latency, consistency, and blast radius. We want every segment request answered in single-digit milliseconds with zero round trip to a central system, we want a canceled subscription to stop working within seconds rather than hours, and we want a single leaked credential or shared token to expose at most a tiny window of access rather than an entire subscription’s remaining lifetime. We need to solve for short-lived, locally verifiable tokens, device binding that makes token sharing across accounts costly, and a revocation propagation system fast enough that the token’s own expiry becomes the true worst-case exposure window, not the exception to it.

Requirements and Constraints

Functional Requirements

  • Issue a short-lived playback authorization token (PAT) after verifying an active subscription and a bound device
  • Bind each issued license to a specific device fingerprint and enforce a per-account cap on concurrently active devices
  • Renew a token transparently while a subscriber keeps watching, without forcing a full re-authentication
  • Validate every CDN segment request against the current token and a live revocation list without a round trip to origin
  • Revoke access for a specific user, device, or license instantly on cancellation, chargeback, password change, or detected abuse
  • Broker the actual content-key exchange with standard DRM systems (Widevine, FairPlay, PlayReady) after entitlement is confirmed

Non-Functional Requirements

  • Issuance latency: p99 under 150ms for a license request, including the upstream DRM key exchange
  • Edge verification latency: p99 under 5ms per segment request, with zero origin round trips on the happy path
  • Scale: 40 million active subscribers, 3 million concurrent streams at peak, roughly 500,000 edge verifications/sec globally
  • Revocation propagation: new segment requests must be denied within 5 seconds of a revocation event at steady state, with a hard worst-case bound of 90 seconds set by the token’s own TTL
  • Availability: 99.95% for the issuance path; the edge verification path must degrade gracefully, never fail open on a bad signature
  • Device binding: a hard cap of 4 concurrently active devices per account, enforced without false positives on legitimate device upgrades

Constraints and Assumptions

  • We are not designing the Widevine, FairPlay, or PlayReady content decryption module (CDM) internals - we design the broker layer in front of them that decides whether to hand out a license at all
  • Content is assumed already encrypted at rest and packaged into segments; the encoding and packaging pipeline is out of scope
  • The CDN edge runs a small, stateless compute layer capable of executing a verification function per request (the Lambda@Edge / Fastly Compute@Edge model)
  • Billing emits reliable subscription-state-changed events; we do not design the billing or payment system itself
  • Offline, downloaded playback uses a separate long-duration DRM license flow governed by the vendor’s own CDM policy - this post covers the online streaming entitlement path only

High-Level Architecture

The system has six major components: the Entitlement Gateway, the License Server, the Device Registry, the Revocation Service, the CDN Edge Verifier, and the Key Management Service, plus an external dependency on the subscriber’s actual DRM key provider (Widevine or FairPlay).

DRM token vending system architecture overview

A player requests playback and the Entitlement Gateway first checks that the account has an active subscription and a valid session, a cheap check backed by a short-lived cache in front of the billing database. It forwards a passing request to the License Server, which is the core of the system. The License Server checks the Device Registry to either confirm an already-bound device or bind a new one (rejecting the request if the account is already at its device cap), checks the Revocation Service to make sure the account, device, or any prior license for this content is not on the revoked list, then asks the Key Management Service to sign a compact Playback Authorization Token (PAT) with a 90-second TTL. In parallel, it proxies a key request to the upstream DRM provider (Widevine or FairPlay) to obtain the actual wrapped content key for this device’s CDM. Both the PAT and the wrapped key are returned to the player in one response.

From there, the player attaches the PAT to every subsequent segment request it sends to the CDN. The CDN Edge Verifier, running as a small function at each of 200+ points of presence, checks the PAT’s signature, expiry, and membership in a locally replicated revocation bloom filter, entirely without contacting the origin. If a subscription lapses or an account gets flagged mid-stream, the Revocation Service pushes a delta to every edge PoP over a long-lived streaming connection, and the player’s next renewal request (roughly every 70 seconds, 20 seconds before the current PAT expires) gets rejected at the License Server, which re-checks entitlement on every renewal rather than trusting the original grant indefinitely.

Data flows in two distinct loops that run at very different frequencies: a slow, expensive issuance loop that touches the Device Registry, the Revocation Service, the Key Management Service, and an external DRM provider, and a fast, cheap edge verification loop that touches nothing but a local signature check and a local bloom filter, half a million times a second.

Key Insight

The single most important architectural decision is decoupling token issuance (slow, centralized, security-heavy) from token verification (fast, local, stateless). Revocation does not need to synchronously reach every edge before the next request - it only needs to reach the edge before the next renewal, and the token's own short TTL absorbs the gap. This is what lets 500,000 verifications/sec add zero load to any central system.

Component Deep Dives

The Entitlement Gateway

This component’s job is to answer “does this account currently have an active subscription” cheaply enough to run in front of every playback request, without hammering the billing database.

A smart engineer’s first instinct is to check subscription status against the billing database on every playback request, since that is the one place status is guaranteed to be fresh. That works at low volume and falls apart the moment License Server renewals climb into the tens of thousands per second, because billing databases are built for transactional correctness on payment events, not for read volume shaped like a video CDN. We front the billing database with a short-lived cache (5 seconds) keyed by user ID. A 5-second staleness window is a deliberate tradeoff: it is short enough that a cancellation becomes visible on the very next renewal cycle, and long enough to cut effective read volume against billing by more than 95% during sustained playback.

# Entitlement Gateway: cached subscription status check in front of the License Server
# Demonstrates: short-TTL read-through cache, fail-closed on cache and DB miss
import time

ENTITLEMENT_CACHE_TTL_SECONDS = 5

class EntitlementLapsed(Exception):
    pass

def check_entitlement(cache, billing_db, user_id: int) -> str:
    cache_key = f"entitlement:{user_id}"
    status = cache.get(cache_key)
    if status is None:
        row = billing_db.fetch_subscription(user_id)
        if row is None:
            raise EntitlementLapsed(user_id)
        status = row["status"]
        cache.set(cache_key, status, ex=ENTITLEMENT_CACHE_TTL_SECONDS)

    if status not in ("active", "trial"):
        raise EntitlementLapsed(user_id)
    return status

Premium Content

Unlock the full article along with everything else in the archive — all in one place.

In-depth analysis Expert insights Full archive access
Unlock Full Article