Open-source project
aws-samples/cloudfront-authorization-at-edge avatar
aws-samples/cloudfront-authorization-at-edge

CloudFront authorization@edge puts Cognito in front of S3 downloads with cookies

Protect downloads of your content hosted on CloudFront with Cognito authentication using cookies and Lambda@Edge

533 stars165 forksTypeScriptMIT-0

At a glance

What is it?
This AWS sample implements authorization at the CDN edge with Lambda@Edge and Cognito, moving JWTs through cookies so that a browser needs no special handling to fetch protected content from CloudFront. It suits teams shipping static sites or single page apps behind CloudFront who want a working reference rather than a product, and the authors ask you to treat it as an illustration to be adapted.
Who is it for?
Teams that serve static content or a single page app through CloudFront and want private access without running an application server on every request are the people this sample is for, and the choice of cookies over headers is what removes the need to change the client.
Can I use it commercially?
Yes. MIT-0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 11 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem is protecting downloads from unauthenticated users

The repository exists to accompany a blog post, and the blog post states the problem in its title: using cookies to protect Amazon CloudFront content from being downloaded by unauthenticated users. The solution explained there puts Cognito authentication in front of S3 downloads from CloudFront, using Lambda@Edge, with JWTs transferred using cookies to make authorization transparent to clients. That last clause is the design decision that everything else follows from. A request to a CloudFront distribution normally carries nothing that identifies the user, so a signed URL or a header has to be added by the client, and a browser application has to be written to add it. Cookies travel on their own. The other thing the repository is explicit about is its own status, saying the purpose is to demonstrate how Lambda@Edge can be used to implement authorization with Cognito as the identity provider, and that the code should be treated as an illustration, to be reviewed thoroughly and adapted before use for serious things. That framing is worth taking at face value.

Seven Lambda@Edge functions, each with one job

The function list in src/lambda-edge is the clearest view of how the flow is split. check-auth is the one on the hot path, checking each incoming request for valid JWTs in the request cookies. parse-auth handles the redirect from the Cognito hosted UI after the user signs in, and refresh-auth handles JWT refresh requests, and sign-out handles sign-out. Then there are two that are not strictly about authentication: http-headers sets HTTP security headers as good practice, and rewrite-trailing-slash appends index.html to paths that end with a slash, which is optional and intended for static site hosting, controlled through the parameter RewritePathWithTrailingSlashToIndex. A shared directory holds utility functions used by several of them. The division is a sensible one, because the check that every request goes through is small, and the functions that talk to Cognito or manipulate cookies are not, and separating them keeps the replicated function code small.

Cookies rather than headers, and the sibling project

The readme spends a section explaining a choice that would otherwise look arbitrary. This repository is described as the sibling of another aws-samples project, authorization-lambda-at-edge, and the difference is that the other one uses HTTP headers rather than cookies to transfer the JWTs. The readme calls that a valid approach while naming the downside: your web application, in particular a single page app, has to be altered to pass those headers along, because browsers do not send them automatically, whereas they do send cookies. That is the whole trade. Headers keep the token out of the cookie jar, but they make every client a participant in the authentication scheme, and a static site has no place to put that logic. The cookies approach pushes the work to the edge and leaves the client untouched, which is what makes the sample usable with a plain S3-hosted site.

Seven CloudFormation custom resources do the awkward parts

A template is only half of a deployment, and the custom resources under src/cfn-custom-resources cover the parts a template cannot express. us-east-1-lambda-stack is a Lambda function implementing a custom resource that makes sure the Lambda@Edge functions are deployed to us-east-1, which the readme calls a CloudFront requirement. user-pool-client updates the User Pool client with the OAuth configuration, and user-pool-domain looks up the User Pool domain where the Hosted UI lives. lambda-code-update injects configuration into the Lambda@Edge functions and publishes versions, and generate-secret generates a unique secret on deployment. Two more build the sample content: react-app builds a sample React app and uploads it to S3, and static-site uploads the sample static site. Each of these is a small Lambda with one job, and the reason they exist is that a Lambda@Edge function has to be replicated to every region in the distribution and versioned, and a Cognito user pool client has to be updated after the domain exists.

One click from the Serverless Application Repository

Deployment is the part the sample has made easiest. The solution can be deployed to your AWS account with a few clicks from the Serverless Application Repository, and the readme gives the console link with the application ARN for the cloudfront-authorization-at-edge application in us-east-1. There are three options in total. The second is to include the Serverless Application in your own CloudFormation template or CDK code, and the example-serverless-app-reuse directory contains example SAM templates and CDK code showing exactly how. The third is to deploy with the SAM CLI, and the prerequisites listed are Node.js, the AWS SAM CLI, and an AWS account with the permissions needed to create resources in it, with a note that your AWS credentials must be findable during deployment. The reuse example is the option that matters for anyone who does not want a one-off environment, since it turns the whole solution into a component you can reference from infrastructure you already maintain.

The template is SAM, the functions are TypeScript, the build is webpack

The build setup is conventional and visible in the repository layout. The template.yaml at the root is the SAM template that comprises the solution, webpack.config.js is the webpack config for the Lambda@Edge functions, and tsconfig.json is the TypeScript configuration for the project, so the edge functions are written in TypeScript and bundled. The package.json names the package cloudfront-authorization-at-edge and the description says it protects downloads of content hosted on CloudFront with Cognito authentication using Lambda@Edge. The scripts section shows the build pipeline, where build removes the webpack output and then runs webpack, and where analyze produces a webpack profile and pipes it into webpack-bundle-analyzer.

json
  "name": "cloudfront-authorization-at-edge",
  "scripts": {
    "webpack": "webpack --progress",
    "build": "npm run remove-webpack-output && npm run webpack"
  },

The test script is a placeholder that exits with an error, and saying so plainly in the package file is more useful than pretending. The runtime dependencies are small and specific: aws-jwt-verify for verifying the tokens, cookie for parsing and setting them, aws-sdk for the service calls, and s3-spa-upload for pushing a single page app to S3. The build tooling is TypeScript with ts-loader, terser-webpack-plugin for minification, prettier for formatting with a tab width of two, and html-loader for the inline HTML in the templates.

Building your own version with the cognito-at-edge library

If the sample's structure does not fit, the readme points to a second route. The repository contains a complete Auth@Edge solution, which the readme defines as predefined Lambda@Edge code combined with a CloudFormation template and various CloudFormation custom resources that enable one-click deployment, and it says the template has various parameters to support multiple use cases, for example bringing your own User Pool or your own CloudFront distribution. But if you want full control and implement an Auth@Edge solution yourself, the NPM library cognito-at-edge from awslabs may be of use. It implements the same functionalities as the solution in this repository, but wrapped conveniently as an NPM package that you can include in your Lambda@Edge functions. The distinction is between a finished assembly and a library: the sample is a deployable arrangement with a deployment path, and the library is the same logic packaged for you to wire into functions you write.

Where this sample is the wrong choice

The first wrong case is a service that needs a supported security product, because the repository asks you to review the code thoroughly and adapt it before relying on it, and there is no version compatibility promise attached to a Lambda@Edge sample. The second is a team that has decided headers are the right mechanism, because the sibling project exists for that case and choosing cookies here means accepting the client's involvement or accepting that a plain browser will not carry the header. The third is a deployment that cannot create resources in us-east-1, since CloudFront requires the edge functions to live there and the custom resource only solves the mechanics, not the permission. The fourth is a content model with real authorisation logic, since what is demonstrated is authentication in front of a bucket rather than per-object or per-role authorisation, and a content catalogue with different access rules needs more than a signed request. The fifth is a team that wants server side rendering or any dynamic behaviour, because everything here serves static files from S3 through CloudFront, and the sample app exists only to show the client reading the JWTs from cookies with the AWS Amplify Framework.

Editorial conclusion

Teams that serve static content or a single page app through CloudFront and want private access without running an application server on every request are the people this sample is for, and the choice of cookies over headers is what removes the need to change the client. It is the wrong choice for a team that needs a supported, hardened security product, because the repository itself asks you to treat the code as an illustration, to review it thoroughly and adapt it, and to use it for serious things only after doing so. Check three things before you adopt it: that the Lambda@Edge functions can be deployed to us-east-1, which is a CloudFront requirement the repository solves with a custom resource, that your application can live with cookies carrying the tokens, since the sibling project uses HTTP headers and the readme is explicit that headers require the web app to pass them along, and that you are comfortable with a Cognito hosted UI redirect flow, because the parse-auth function handles the redirect after sign-in. The licence is MIT-0, the last push was on 2026-10-12, and the newest tagged release is v2.3.2 from 2024-09-25.

Frequently asked questions

What does the cloudfront-authorization-at-edge sample do?

It puts Cognito authentication in front of S3 downloads from CloudFront using Lambda@Edge, transferring JWTs using cookies so that authorization is transparent to clients. The repository says the purpose is to demonstrate how Lambda@Edge can be used to implement authorization with Cognito as the identity provider.

Why does the sample use cookies instead of HTTP headers to carry the JWTs?

Because browsers send cookies automatically but do not send custom HTTP headers, so with headers your web application, in particular a single page app, has to be altered to pass them along. The sibling aws-samples project authorization-lambda-at-edge uses headers instead, and the readme calls that a valid approach with that drawback.

Which Lambda@Edge functions does the sample include?

check-auth checks each incoming request for valid JWTs in the request cookies, parse-auth handles the redirect from the Cognito hosted UI after sign-in, refresh-auth handles JWT refresh requests, sign-out handles sign-out, http-headers sets HTTP security headers, rewrite-trailing-slash optionally appends index.html to paths ending in a slash, and a shared directory holds utility functions.

How do I deploy the cloudfront-authorization-at-edge solution?

Three ways: with a few clicks from the Serverless Application Repository, by including the Serverless Application in your own CloudFormation template or CDK code using the example-serverless-app-reuse directory, or with the SAM CLI, which requires Node.js, the AWS SAM CLI and an AWS account with the necessary permissions.

Can I build my own Auth@Edge solution instead of deploying the sample?

Yes. The readme points to the NPM library cognito-at-edge from awslabs, which implements the same functionalities as this solution but wrapped conveniently as an NPM package you can include in your Lambda@Edge functions. The sample itself is predefined Lambda@Edge code plus a SAM template with custom resources for one-click deployment, and it also carries parameters for bringing your own User Pool or CloudFront distribution.

Official sources

  1. aws-samples/cloudfront-authorization-at-edge on GitHub
  2. License: MIT-0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/aws-samples-cloudfront-authorization-at-edge.svg)](https://hysenlabs.com/projects/aws-samples-cloudfront-authorization-at-edge)

Was this useful?