AWS Feed
Protecting your media assets with token authentication
This post was authored by Osmar Bento and Arturo Velasco, Media and Entertainment Solution Architects at AWS.
Video streaming is no longer exclusively done by media companies. Schools, ecommerce retailers, tech companies, and banks are creating media content to distribute directly to their consumers. Video streaming, both live and on-demand, has become the prevailing communication tool to reach the target audiences. As the value and number of media assets grow, creating a secure distribution workflow to ensure that only the intended audiences have access.
Amazon CloudFront authentication methods
Companies that distribute media content over the internet need to protect their media streams to prevent unauthorized access and redistribution of their assets. Amazon CloudFront gives you the ability to serve private content with signed URL and signed cookies. You can also use token authentication by adding Lambda@Edge to your distribution. Lambda@Edge is a feature of Amazon CloudFront that lets you run code closer to users of your application, which improves performance and reduces latency. The following are options to securely serve private content using CloudFront:
- Require that your users access your private content using special CloudFront signed URLs or signed cookies.
- Require that your users access your content using CloudFront URLs, not URLs that access content directly on the origin server (for example, Amazon Simple Storage Service (Amazon S3) or a private HTTP server).
- Requiring CloudFront URLs isn’t necessary, but we recommend it to prevent users from bypassing the restrictions that you specify in signed URLs or signed cookies.
- With Lambda@Edge, require users to provide JSON Web Tokens (JWTs) to access the private content.
In this post, we show you how to implement token authentication for Amazon CloudFront Distribution using Lambda@Edge, to protect your on-demand and live OTT distributions.
JSON Web Tokens using Lambda@Edge
JSON Web Tokens (JWTs) are an open standard for securely sharing private data information as JSON objects. JWTs are digitally signed using a 256 bits secret key, so the information can be verified and trusted.
With Lambda@Edge you can create custom functions and run them at AWS Regions and Amazon CloudFront edge locations.
You can use Lambda functions to change CloudFront requests and responses at the following points:
- After CloudFront receives a request from a viewer (viewer request)
- Before CloudFront forwards the request to the origin (origin request)
- After CloudFront receives the response from the origin (origin response)
- Before CloudFront forwards the response to the viewer (viewer response)
Architecture overview
Solution components
In this post, we walk through the implementation of the component in the web APP (GitHub repository). We also go through the cloud components for authentication, token validation, and CDN caching.
The frontend and backend AWS resources are built using AWS Amplify, an end-to-end solution that enables mobile and front-end web developers to build and deploy secure, scalable full-stack applications. With Amplify, you can configure app backends in minutes, connect them to your app in just a few lines of code, and deploy static web apps in three steps.
The web app is built in React and uses Video.JS as the video player.
After successful authentication, Amazon Cognito returns user pool tokens to your application. Then, you can use the token to grant access to the backend resources. In the proposed architecture, the token is used for signing the requests for media stream content, Lambda@Edge function decode and validate the token attributes, authenticating the spectator to watch the content.
Deployment steps
1) Project dependencies
To build the integration with AWS components and host our web application we use AWS Amplify.
For complete steps to install and configure AWS Amplify please visit the documentation (Amplify Documentation for React).
npm install -g @aws-amplify/cli
amplify configure
2) Clone the repository
git clone https://github.com/aws-samples/cloudfront-secure-media.git
cd secure-url-cf
npm install
amplify init --app https://github.com/aws-samples/cloudfront-secure-media.git
amplify init
amplify push
3) Start your local environment
npm start
It should load the authentication page. Now you can create your first account and sign in.
After the login, it should load the following local website:
4) Add some videos resources to an Amazon S3 bucket
We used Amplify Video to create some test VOD content. Amplify Video is an open-source plugin for the Amplify CLI, that makes easy to incorporate video streaming to your web or mobile applications. Powered by AWS Amplify and AWS Media Services. Amplify video also support live workflows. For more options and sample implementations, please visit amplify-video GitHub.
npm i amplify-category-video -g amplify add video
? Please select from one of the below mentioned services: Video-On-Demand
? Provide a friendly name for your resource to be used as a label for this category in the project: vod-wf-jwt
? Select a system-provided encoding template, specify an already-created template name: Default HLS Adaptive Bitrate
? Is this a production environment? Yes
? Do you want to protect your content with signed urls? No
? Do you want Amplify to create a new GraphQL API to manage your videos? (Beta) No
✔ All resources built. amplify push
Amplify Video creates the Amazon S3 bucket to store the source content, the transcoded content, and it also deploys the CloudFront distribution. Please see the sample result of amplify push
:
Video on Demand: Input Storage bucket:
vodcfjwt-dev-input-SOMEID Output URL for content:
https://someid.cloudfront.net (https://someid.cloudfront.net/)
Note: Amplify Video also offers the option to protect the content with signed URL. You can find more information on how to use signed url using Amplify Video here: Getting Started with VOD.
Test transcoding
Navigate to the Amazon S3 console. Amplify Video deployed a few buckets into your environment. Select the input
bucket and upload a .mp4
file you have stored locally on your computer.
Once the file has been successfully uploaded, navigate the AWS Elemental MediaConvert console to see your transcode job kicked off. This job takes the input file, transcodes it into the Apple HTTP Live Streaming Protocol (HLS), and outputs the segment files to the Amazon S3 bucket labeled output.
Testing media playback
After the MediaConvert job reaches a completed state, navigate back to the Amazon S3 console, and locate the output bucket. When you look in the bucket, you should see a folder with the name of the file you uploaded. In the folder you should see the output files created by MediaConvert. Locate the HLS Manifest, the file with the .m3u8 extension, then replace the Amazon S3 domain by the Output URL for content.
The format of the playable URL is Output URL for content
+ /name of the asset/ + name of the asset.m3u8
Example: https://someid.cloudfront.net/BigBuckBunny/BigBuckBunny.m3u8
5) Add JWT authentication to your Amazon CloudFront distribution
a) Install the dependencies of Lambda@Edge JWT authentication
cd amplify/backend/function/jwtauth/src/
npm install
b) Edit the index.js function file and add your Amazon Cognito User Pool attributes
Open the config.js file, located in
amplify/backend/function/jwtauth/src/config.js
List the auth resources created and copy the Cognito user pool id.
amplify auth console
Using service: Cognito, provided by: awscloudformation
? Which console User Pool
User Pool console:
https://us-east-1.console.aws.amazon.com/cognito/users/?region=us-east-1#/pool/us-east-SomeID/details
Current Environment: dev
The Cognito user pool id can be located in the URL returned by running amplify auth console
Copy the Pool Id information and replace it in the var USERPOOLID
var USERPOOLID = 'us-east-1_SomeID';
c) Download and store the corresponding public JSON Web Key (JWK) for your user pool. It is available as part of a JSON.
You can locate the Web Key Set (JWKS) at:
https://cognito-idp.us-east-1.amazonaws.com/us-east-SomeID/.well-known/jwks.json
For more information on JWK and JWK sets, see Amazon Cognito verifying a JSON Web Token documentation and JSON Web Key (JWK).
You can see the sample jwks.json
in JSON Web Token documentation. Next, replace the JWKS with the credentials of your Cognito User Pool.
var JWKS = '{"keys":[{"alg":"RS256","e":"AQAB","kid":"1234exemple=","kty"::"RSA"....}]}
Next, deploy your Lambda function by simply executing amplify push
in the home app folder.
amplify push
6) Deploy to Lambda@Edge
Now that we pushed the function to check the JWT Token to the cloud, we deploy it to our distribution created in Step 5.
a) Go to the CloudFront console, and get the distribution ARN created in Step 5
b. Go to Lambda console, and deploy the function to Lambda@Edge
7) End-to-end tests
Now open your web application and play some test content.
In the video URL field, add the full CloudFront URL of your output asset created in Step 5.
Congratulations. Now you can customize your media content distributions and applications adding authentication protection.
Conclusion
In this blog post, we discussed strategies to protect media streams using JWT token authentication. This helps to reduce unauthorized redistribution of digital content. For further reading, see the Amazon CloudFront documentation to find additional ways to protect private content.
Additional Resources
- Private channels for Amazon Interactive Video Service: https://aws.amazon.com/pt/blogs/media/introducing-private-channels-for-amazon-interactive-video-service/
- AWS Amplify Video: https://aws.amazon.com/blogs/media/introducing_aws_amplify_video/
- Amazon CloudFront using signed URLs: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-signed-urls.html