How Signed URLs Actually Protect Paid Video Content
5 min read
Paid video platforms and EdTech sites can't afford leakages. Learn the cryptography behind Signed URLs, how CDNs validate signatures, and how to implement them to secure your video assets.
If you are running an online course platform, a paid community, or a premium streaming application, video content is your product. However, if your video assets are stored in a simple public bucket or delivered via a generic CDN link, you are highly vulnerable to leakage.
All a user needs to do is inspect the network tab in their web browser, copy the direct source URL of the video (e.g., `https://cdn.yourplatform.com/course1/lecture1.mp4`), and share it. Once that link is leaked, anyone can view, download, or embed your video for free, bypassing your paywall entirely.
To prevent this, production-grade video delivery networks rely on Signed URLs. Here is the technical breakdown of how Signed URLs work, the cryptography behind them, and how they protect paid content.
What is a Signed URL?
A Signed URL is a standard URL that has cryptographic signature parameters appended to it. These parameters specify restrictions on who can access the file, from where, and for how long. The signature proves that the URL was generated by your authorized backend server.
A typical signed URL looks like this:
`https://cdn.yourplatform.com/lecture1.mp4?expires=1783458000&token=8a5f3d9b2c8e10fa71b9c3e...`
The URL includes the file path, an expiration timestamp (`expires`), and a cryptographic hash (`token`) that prevents tampering.
The 3 Core Security Pillars of Signed URLs
Signed URLs protect your content through three primary validation mechanisms:
- Time-Based Expiration (TTL): Each URL is given a short lifetime (e.g., 5 minutes). If a user tries to access the URL after the expiration timestamp has passed, the CDN immediately rejects the request with a 403 Forbidden response. Even if a user copies and posts the link online, it becomes useless within minutes.
- Cryptographic Integrity: The token is generated using a hash-based message authentication code (HMAC-SHA256). It signs the URL path and the expiration timestamp using a secret key known only to your server and the CDN. If a user tries to modify the expiration timestamp to gain longer access, the signature validation fails.
- Optional Client Restrictions: You can bind the URL to a specific client parameter, such as the user's IP address. This ensures that the generated URL will only work on the specific device/network that requested it, making sharing impossible.
The Architectural Flow
Securing a video file with Signed URLs involves a coordination between your frontend, backend, and CDN edge node:
- 1. The User requests a page: A logged-in student visits your video page.
- 2. Authentication Check: Your backend verifies that the user has paid for the course and is logged in.
- 3. Signature Generation: The backend generates the expiration timestamp, compiles the URL string, and signs it using a secret key to output the HMAC token.
- 4. Render: The frontend receives the signed URL and injects it into the video player.
- 5. CDN Edge Verification: When the video player requests the file, the CDN edge (e.g. Cloudflare Worker or AWS CloudFront) intercept the request, recalculates the HMAC signature using the shared secret key, checks if the current time is before the expiration timestamp, and validates the signature match. If valid, the CDN serves the video segment; otherwise, it blocks the request.
How to Generate Signed URLs in Node.js
Here is a clean backend implementation demonstrating how to generate a cryptographically secure HMAC signed URL using Node's native `crypto` module:
```javascript
const crypto = require('crypto');
function generateSignedUrl(filePath, expiryMinutes) {
const secretKey = process.env.CDN_SIGNING_SECRET;
const domain = 'https://cdn.yourplatform.com';
// Calculate expiry epoch time
const expires = Math.floor(Date.now() / 1000) + (expiryMinutes * 60);
// Create the string to sign (path + expiry)
const stringToSign = `${filePath}?expires=${expires}`;
// Create HMAC SHA256 signature
const signature = crypto
.createHmac('sha256', secretKey)
.update(stringToSign)
.digest('hex');
return `${domain}${filePath}?expires=${expires}&token=${signature}`;
}
// Usage
const playerUrl = generateSignedUrl('/lessons/intro.mp4', 5);
console.log(playerUrl);
```
How the CDN Edge Validates the URL
At the CDN edge, a worker script or middleware intercepts incoming requests to inspect the parameters. If you are using Cloudflare, a Cloudflare Worker handles the validation logic at the nearest edge location. It parses the URL, extracts the `expires` and `token` query parameters, calculates the expected HMAC signature using the edge-configured secret, and performs a time-constant comparison. If valid, the request is forwarded to the storage bucket; if invalid, it immediately returns a 403 Forbidden without touching your origin storage.
Summary
Implementing Signed URLs is a mandatory security standard for any commercial video platform. By decoupling authorization from storage and letting your CDN handle cryptographic checks at the edge, you achieve robust content security without overloading your main application servers.
Frequently Asked Questions
Can someone still download a video if it uses Signed URLs?
Yes. If a user has a valid signed URL, they can download the raw video stream within its active expiration window. To prevent simple downloads, you should combine Signed URLs with HLS/DASH streaming (which splits videos into hundreds of small fragments) and, for maximum protection, implement DRM (Digital Rights Management) like Widevine or FairPlay.
What is the recommended expiration time (TTL) for a Signed URL?
The recommended TTL is between 2 to 15 minutes. The signature only needs to be valid long enough for the player to initiate the stream. Once the connection is established and the player begins loading the video segment, expiration changes will not cut off the active stream.
Do Signed URLs degrade CDN caching performance?
By default, yes, because most CDNs treat different query strings (like unique tokens or timestamps) as unique cache keys, leading to cache misses. To fix this, you must configure your CDN (e.g. via Cloudflare Workers or Cache Keys) to strip the token when querying the cache, but validate the signature before serving.
How do you protect the signing key?
The signing key (a cryptographically secure shared secret) must remain strictly on your backend server or edge runtime (e.g., Cloudflare Workers Secrets). It must never be exposed to the client-side code, mobile applications, or frontend git repositories.