StreamVault
Invite-only HLS video streaming on AWS with edge-enforced access control.
Video platform on AWS, Aug 2026 – Sep 2026
End-to-end video platform: an EC2 FFmpeg pipeline produces multi-audio HLS, Cognito with PKCE signs viewers in, a Lambda issues CloudFront signed cookies, and a FastAPI + DynamoDB service syncs watch progress. Infrastructure is defined in AWS CDK.
Problem
Private video needs every playlist and every segment protected, not just the page that embeds them. Signed URLs per segment don’t scale to HLS, where a player requests hundreds of files.
Why it was worth building
Signed-cookie delivery is the standard way to protect segmented video on AWS. Building it end to end, with infrastructure as code, a real auth flow and an encoding pipeline, covers most of what a production media stack needs.
Architecture
- Viewerweb app on CloudFront
- Cognito Hosted UIPKCE authorization code
- Auth LambdaHMAC-signed state, JWT verify
- Signed cookiesHttpOnly, Secure, 4-hour policy
- CloudFrontkey group checks every request
- Private S3.m3u8 + .ts segments
- Raw videomp4 / mkv / mov
- S3 input/pipeline.sh
- EC2 workerc7i.2xlarge, scoped IAM role
- FFmpeglibx264, 10 s HLS segments, multi-audio
- S3 output/catalog updated, web redeployed
Technical decisions
Signed cookies instead of signed URLs
One cookie policy covers every playlist and segment under the distribution, so the player needs no URL rewriting and access is still checked at the edge on every request.
PKCE with HMAC-signed state
The auth Lambda generates the PKCE verifier and signs the state with a secret in Secrets Manager, stores it in a short-lived HttpOnly cookie scoped to /auth, and verifies the Cognito ID token before issuing CloudFront cookies.
Everything in CDK
User pool, hosted UI domain, CloudFront public key and key group, secrets, HTTP API and the EC2 worker role are all declared in one stack, so the environment can be rebuilt from scratch.
Short-lived compute for encoding
Encoding runs on an EC2 worker launched per job instead of an always-on server, so compute is only billed while it works.
Challenges
Cookie scope and SameSite
Auth-state cookies use SameSite=Lax so the Cognito redirect can return them, while CloudFront cookies are cleared with Strict on sign-out.
What I built
- Auth Lambda in TypeScript with aws-jwt-verify, with unit tests for the PKCE crypto.
- FastAPI progress API validating Cognito RS256 JWTs against JWKS, persisting to DynamoDB, and containerized with Docker.
- HLS.js player with audio-track and WebVTT subtitle switching.
- Single-command pipeline: scan, upload, launch EC2 encode, sync HLS output, update catalog, redeploy.
Results
- Every playlist and segment is protected at the CDN edge; the bucket is never public.
- Reproducible infrastructure from a single CDK deploy.
Takeaways
- For HLS, the access-control unit is the distribution path, not the file.
- Auth flows fail in the details (cookie paths, SameSite, expiry), so test them explicitly.
What I'd do next
- Run the encode worker on Spot capacity with interruption handling to cut encoding cost further.
- Adaptive bitrate ladders (multiple renditions) instead of a single rendition.