Architecture Overview
┌─────────────┐ ┌──────────────────┐ ┌─────────────┐
│ Browser │────▶│ x402 Proxy │────▶│ Video CDN │
│ (HLS.js) │◀────│ (Express) │◀────│ (Mux) │
└─────────────┘ └──────────────────┘ └─────────────┘
│ │
│ ▼
│ ┌──────────────────┐
│ │ x402 Facilitator│
│ │ (Payment) │
│ └──────────────────┘
│ │
▼ ▼
┌─────────────┐ ┌──────────────────┐
│ Wallet │ │ Base Network │
│ (MetaMask) │ │ (USDC) │
└─────────────┘ └──────────────────┘
JWT Token Structure
After successful payment, we issue a JWT containing the playbackId and expiration time:
{
"playbackId": "ABC123...",
"iat": 1733400000, // Issued at (Unix timestamp)
"exp": 1733486400 // Expires at (24 hours later)
}The token is signed with a server-side secret using HS256. Tokens cannot be forged without the secret key.
Cookie Strategy
We use per-video cookies to allow access to multiple videos:
x402-ABC123=eyJhbGc... // Token for video ABC123 x402-XYZ789=eyJhbGc... // Token for video XYZ789 x402-viewing=token... // Current viewing session
Middleware Chain
Each segment request goes through this middleware chain:
x402 Payment Protocol
The x402 protocol uses EIP-3009 (TransferWithAuthorization) for gasless USDC transfers:
{
"domain": {
"name": "USDC",
"version": "2",
"chainId": 84532, // Base Sepolia
"verifyingContract": "0x..." // USDC contract
},
"message": {
"from": "0x...", // Viewer wallet
"to": "0x...", // Creator wallet
"value": "50000", // $0.05 (6 decimals)
"validAfter": "...",
"validBefore": "...",
"nonce": "0x..."
},
"primaryType": "TransferWithAuthorization"
}The facilitator receives this signed message and executes the actual USDC transfer on-chain.
Security Considerations
🔐 JWT Secret
Store JWT_SECRET in environment variables. Never commit to source control.
🔄 Token Replay
Tokens are bound to playbackId. Cannot use one video token to access another video.
⏰ Expiration
24-hour expiry limits damage from token theft. Can be configured shorter.
🌐 HTTPS
In production, use HTTPS and set secure: trueon cookies.
Environment Variables
# Required ORIGIN_BASE_URL=https://stream.mux.com WALLET_ADDRESS=0x... # Fallback wallet MUX_TOKEN_ID=... # Video CDN credentials MUX_TOKEN_SECRET=... # Optional JWT_SECRET=... # Random 32+ char string NETWORK=base-sepolia # or base-mainnet ASSET_PRICE=$0.01 # Per-segment price FACILITATOR_URL=https://x402.org/facilitator PORT=4000