Access Control for SVOD Platforms
Edge Key & Access Control for SVOD Platforms
This guide covers video access management for platforms with multiple content tiers: free, subscription, and purchase/rental.
Core Concept
AntCDN doesn’t know who your users are. It doesn’t have accounts, subscriptions, or payment info.
Your backend handles:
- User authentication
- Subscription/purchase verification
- JWT token generation
AntCDN validates: “Is this JWT valid for this edge key?”
This separation gives you full control over your business logic.
Edge Key Strategy
Recommendation: One private edge key per video, created at upload time.
const assetId = await uploadVideo(file);const edgeKey = await createEdgeKey(assetId, { label: "primary", isPrivate: true // Always private for paid platforms});
await db.videos.insert({ asset_id: assetId, edge_key: edgeKey, content_tier: "subscription" // or "free", "purchase"});The Access Flow
User clicks "Play" │ ▼┌─────────────────┐│ Your Backend │ 1. Authenticate user│ │ 2. Check access (subscription? purchased?)│ │ 3. Generate JWT token│ │ 4. Return playback URL└────────┬────────┘ │ ▼┌─────────────────┐│ AntCDN │ Validates JWT → Serves video└─────────────────┘Database Schema
CREATE TABLE videos ( id UUID PRIMARY KEY, title TEXT NOT NULL, asset_id TEXT NOT NULL, edge_key TEXT NOT NULL, content_tier TEXT NOT NULL, -- 'free', 'subscription', 'purchase' price_cents INTEGER, rental_hours INTEGER);
CREATE TABLE purchases ( id UUID PRIMARY KEY, user_id UUID REFERENCES users(id), video_id UUID REFERENCES videos(id), purchase_type TEXT NOT NULL, -- 'buy' or 'rent' expires_at TIMESTAMP -- NULL for purchases, set for rentals);Backend Authorization
// POST /api/videos/:videoId/playback-urlasync function getPlaybackUrl(req, res) { const { videoId } = req.params; const user = req.user;
const video = await db.videos.findById(videoId);
// Check access based on content tier const hasAccess = await checkAccess(user, video); if (!hasAccess) { return res.status(403).json({ error: "Access denied" }); }
// Generate JWT const token = generateVideoToken(user.id, video.edge_key); const playbackUrl = `https://worker.antcdn.net/v1/${video.edge_key}/master.m3u8?jwt=${token}`;
return res.json({ playbackUrl });}
async function checkAccess(user, video) { switch (video.content_tier) { case 'free': return true;
case 'subscription': return user?.subscription_expires_at > new Date();
case 'purchase': const purchase = await db.purchases.findOne({ user_id: user?.id, video_id: video.id }); if (!purchase) return false; if (purchase.purchase_type === 'buy') return true; return purchase.expires_at > new Date();
default: return false; }}@app.route('/api/videos/<video_id>/playback-url', methods=['POST'])def get_playback_url(video_id): user = get_current_user() video = db.videos.find_by_id(video_id)
if not check_access(user, video): return jsonify({"error": "Access denied"}), 403
token = generate_video_token(user.id, video.edge_key) playback_url = f"https://worker.antcdn.net/v1/{video.edge_key}/master.m3u8?jwt={token}"
return jsonify({"playbackUrl": playback_url})
def check_access(user, video): if video.content_tier == 'free': return True elif video.content_tier == 'subscription': return user and user.subscription_expires_at > datetime.now() elif video.content_tier == 'purchase': purchase = db.purchases.find_one(user_id=user.id, video_id=video.id) if not purchase: return False if purchase.purchase_type == 'buy': return True return purchase.expires_at > datetime.now() return FalseJWT Token Generation
import jwt from 'jsonwebtoken';
const SIGNING_KEY = process.env.ANTCDN_SIGNING_KEY;
function generateVideoToken(userId, edgeKey) { return jwt.sign( { sub: edgeKey, uid: userId, exp: Math.floor(Date.now() / 1000) + (4 * 60 * 60) // 4 hours }, SIGNING_KEY, { algorithm: 'HS256' } );}Token Lifetime Recommendations:
| Content Type | Token Lifetime |
|---|---|
| Free | 24 hours |
| Subscription | 4-8 hours |
| Rental | min(rental_expires, 4 hours) |
| Purchase | 4-8 hours |
Common Questions
Should I create multiple edge keys per video?
No. One private edge key per video is sufficient. The JWT controls access.
How does AntCDN know who my user is?
It doesn’t need to. AntCDN only validates:
- Is the JWT signature valid?
- Is it for this edge key? (
subclaim) - Is it unexpired?
What if a user shares the playback URL?
JWTs expire (e.g., 4 hours). Short-term sharing is possible, long-term is not.
For higher security:
- Shorter token lifetimes
- Concurrent stream limits (track on your backend)
How do I handle free content?
Two options:
Option A: Public edge keys for free content (no JWT needed)
Option B: Private edge keys, but always grant access in your backend
Option B is better for consistency and analytics.
Summary
| You Control | AntCDN Controls |
|---|---|
| User authentication | Video storage |
| Subscription/purchase logic | CDN delivery |
| Token issuance | JWT validation |
| Business rules | Edge key → video mapping |
Your backend is the gatekeeper. AntCDN is the delivery truck.