Protecting Static Websites with Cognito in AWS

Cem Onan
Orion Innovation techClub
5 min readMay 25, 2023

S3 buckets are great for hosting static web pages. However, that makes your content publicly accessible, too. One way to protect your pages is by adding authorization on top of them. With this project, using a CloudFront distribution, Lambda@Edge functions, and a Cognito user pool; a user login page and JWT authorization logic will be implemented in front of your static website in S3. Also, this system will make sure the JWT token is saved into browser cookies once a user logged in so that the user will not need to re-login on its next attempts. AWS CDK is used as IaC (Infrastructure as Code) tool in this project to provision all above-mentioned resources into the AWS cloud programmatically. By changing some parameters regarding your needs, you can deploy the same solution into your account as well without bothering on the AWS console.

Solution Architecture

The following diagrams represent the behaviors of the system.

1. Unauthenticated User Tries to View Website

CloudFront sits in front of your S3 bucket and receives all the requests. It’s possible to intercept requests and responses with a special type of Lambda function (Lambda@Edge). Here, in this example, the default handler function intercepts all viewer requests except the ones made into /callback path. Its responsibility is to check whether a JWT exists in the client’s browser or not. In this case, the user does not have a JWT since it has not logged in yet. So the default handler function gets the login page URL from the SSM parameter store and returns an HTTP 301 response to redirect the client to a login page (Cognito user pool hosted UI).

The solution diagram represents the unauthenticated access flow.
The solution diagram represents the unauthenticated access flow.
Amazon Cognito user pool client hosted UI
Amazon Cognito user pool client hosted UI

2. Login Flow

Cognito user pools are simply user databases for your web and mobile applications in which you can implement OAuth flows for these users’ authorization. You can even connect any identity provider to your user pools so that your users can sign in with familiar services such as Google login, Facebook login, Okta login, etc. But in this example, for the sake of simplicity, no identity provider is integrated. Instead, email and password-based simple authentication is implemented. Cognito user pool also allows you to create user pool clients so that you can have an AWS-generated hosted UI page your users can visit to sign in. Users can obtain a code from Cognito as long as their credentials are valid.

Suppose our client has logged in successfully and redirected to the callback URL by Cognito. In the query string parameters of callback URL, authorization code and a particular query string parameter called state can be found, in the previous flow Default Handler function had embedded the requested URL into that state parameter. So here Callback Handler receives the request. It extracts the requested URL from the state query string parameter. Fetches some necessary credentials and parameters from SSM Parameter store and exchanges authorization code with a JWT (ID token) against Cognito Token endpoint. Finally, once the JWT is obtained, it saves the JWT into browser cookies and redirects the client back to the requested URL.

Solution diagram represents the login flow
The solution diagram represents the login flow

3. Authenticated User Tries to View Website

At this step, similar to the 1st one, the request is intercepted by the Default Handler once more. Since the user now has the JWT token in its cookies, the Default Handler validates the JWT against the Cognito user pool client. As long as the provided JWT is valid and not expired, the Default Handler returns the request intact to CloudFront. At this point, you may consider using an access token instead of an ID token and implementing any additional custom authorization logic based on the claims provided in that JWT but for the sake of simplicity we assumed that there is only one type of authenticated users and it’s enough to authorize them as long as their ID token is verified against the issuer. Finally, CloudFront gets the requested object (index.html file) from the S3 bucket and returns it to the client.

The solution diagram represents the authenticated client’s access flow
The solution diagram represents the authenticated client’s access flow
A screenshot taken from Chrome DevTools to show that ID token is saved into cookies once the user has logged in for further access requests without a need to login.
A screenshot taken from Chrome DevTools shows that the ID token is saved into cookies once the user has logged in for further access requests without a need to log in.

Deploying This Application to AWS

1. Ensure you have installed Docker and AWS CDK on your computer.

Here are some quick links if you don’t have them installed yet:

2. Make sure that you have your AWS CLI credentials, they have sufficient permissions to create bootstrapping and deployment of the CDK stack.

If you don’t have your AWS CLI credentials yet, visit the following link and create your Access Key and Secret Access Key under the My Security Credentials menu at IAM Console.

https://console.aws.amazon.com/iam?p=iam&cp=bn&ad=c

IAM Console
IAM Console

3. Bootstrap the CDK Application

Open a terminal at the root directory of the project and run the following command:

$ cdk bootstrap

4. Deploy the CDK Application

Open a terminal at the root directory of the project and run the following command:

$ cdk deploy --context CDK_AWS_ACCOUNT_ID={your aws account ID} --context CDK_ENV={your environment name e.g. staging or prod} --context CDK_APP={your app. name}

Once the build artifacts become ready to be deployed, CDK will prompt you for your consent to execute the changeset.

CDK changeset execution prompt
CDK changeset execution prompt

Allow changeset execution, and then you can keep track of the deployment status live in your terminal.

A screenshot represents the CDK deployment status
A screenshot represents the CDK deployment status

Links

--

--

Cem Onan
Orion Innovation techClub

Software Developer at Orion Innovation, cloud development enthusiast.