Pratham Shah

Protecting HLS video with CloudFront signed cookies

Why signed cookies fit HLS better than signed URLs, and how StreamVault issues them after a Cognito PKCE sign-in.

, Cloud, AWS, Security

An HLS player doesn’t request one video file. It requests a master playlist, then a media playlist, then a segment every few seconds. Signing each URL means rewriting playlists on the fly. A signed cookie scoped to the distribution path covers every request the player makes, and CloudFront validates it at the edge before anything reaches S3.

The sign-in flow

Sign-in
  1. /auth/loginPKCE verifier + HMAC-signed state
  2. Cognito Hosted UIauthorization code
  3. /auth/callbackverify state, redeem code
  4. Verify ID tokenaws-jwt-verify
  5. Set cookiesCloudFront-Policy, -Signature, -Key-Pair-Id

The Lambda keeps the PKCE verifier in a short-lived HttpOnly cookie scoped to /auth and signs it with a secret from Secrets Manager, so a tampered or replayed state is rejected before the code is redeemed. After the ID token verifies, it writes a custom policy that allows the viewer domain for four hours:

const policy = JSON.stringify({
  Statement: [{
    Resource: `https://${config.viewerDomain}/*`,
    Condition: { DateLessThan: { "AWS:EpochTime": Math.floor(expiresAt.getTime() / 1000) } },
  }],
});

Details that matter

  • Every cookie is HttpOnly and Secure, so page scripts can’t read the signature.
  • The auth-state cookie uses SameSite=Lax so it survives the redirect back from Cognito.
  • Sign-out clears all three CloudFront cookies and the state cookie explicitly.
  • The public key, key group, user pool, secrets and API are declared in one CDK stack, so the setup is reproducible.

Takeaway: for segmented media, the unit of access control is a path prefix, not a file.