# CS178 Project 2: Amazon Cognito In this tutorial, we will learn the basics of Amazon Cognito, an AWS User Authentication and Access Control service. This will walk through a step-by-step demo that creates a simple locally hosted web app with an Amazon Cognito powered login/signup. ## What is Amazon Cognito? [Amazon Cognito | Amazon Web Services](https://www.youtube.com/watch?v=vqAirwfYgrY&t=73s) **Amazon Cognito offers secure and flexible sign up and sign in features, with a customizable UI for your branding/theme.** The security features even includes 'intelligent bot detection'. It supports email/password login, social login (such as Google, Facebook, Apple), Multi-factor authentication (MFA), and many other functions. **It allows developers to focus their attention/resources on other parts of their application, without having to worry about creating a user database or security.** It can connect to other AWS services or your own third party integrations. ## Pricing You are charged based on the number of monthly active users (MUAs) in your account. It is **free** for up to 10,000 MAUs and $0.015 per every MAU after that. There is separate pricing for using SMS or Email Messages for MFA and user verification because those features fall under Amazon Simple Notification Service (SNS) and Amazon Simple Email Service (SES). ## Pools Amazon Cognito has two main components that serve different roles in handling authentication and authorization: **User Pools** and **Identity Pools**. 1. **User Pools: Who are you?** It is like a user directory. It stores and manages user profiles, passwords, and sign-in methods. When someone signs up or logs in, they're interacting with the user pool. The User Pool issues **authentication tokens (JWTs)** to prove the user's identity to your app and keep track of their log-in data. **Example Use**: A user logs into your app using their username and password. Cognito verifies that they are in fact a part of the User Pool, and then returns a token to your app that you can use to identify that user. 2. **Identity Pools: What are you allowed to do?** An identity pool is all about authorization. It determines what a user can access *after* they've logged in. It is used for temporary access to AWS resources such as S3 or DynamoDB after they log in, and works with federated identities, like Google # Demo Here is a quick [Walthrough Video](https://youtu.be/jWrWSsUD_tE) demonstrating what we will accomplish in the tutorial. The detailed steps are below: ## Create HTML Site Upon creating a User Pool/App Client, Cognito actually gives you code that you can use to create an app under their Quick setup guide using Golang, Java, NodeJS, or Python. I wanted to follow the Python directions to create a Flask App demo of this, but there were issues that I could not solve related to permissions. Therefore, I found this tutorial [How to use AWS Cognito to build an Authentication / Login System](https://www.youtube.com/watch?v=8a0vtkWJIA4) that walks you through creating a simple locally hosted site using HTML. In VSCode, create three .html files: **index.html**, **logged_in.html**, and **logged_out.html** in the same folder. ![Screenshot 2025-05-11 at 3.40.02 PM](https://hackmd.io/_uploads/HJENjtRglx.png) *All three files will have hrefs that say "#" because they do not contain a link yet. We will replace these with the correct links after we create the User Pool/App Client* 1. **index.html:** This is the homepage of your site. It contains a link labeled Register or Login that will eventually take you to our Cognito powered Login. ``` <body> <h3>Welcome to my Website</h3> <p><a href ="#">Register or Login</a></p> </body> ``` 2. **logged_in.html:** This is the page that shows once you have successfully logged in. There is a link labeled Log out that will eventually take you to the logged out page. ``` <body> <h1>Congratulations!</h1> <p>You are now logged in.</p> <a href="#">Log out</a> </body> ``` 3. **logged_out.html:** This is the page that shows after you have logged out. There is a link labeled Log back in that will take you back to the Cognito powered Login. ``` <body> <h2>You are logged out</h2> <p><a href ="#">Log back in</a></p> </body> ``` 4. If you have not already installed python, install using [python.org](https://www.python.org/downloads/) 5. Make sure you are in your correct directory, and run this in the terminal to launch your site: ``` python3 -m http.server ``` 6. Once it has launched, go to localhost:8000 in your browser and you should see your index.html page! *Remember, the link will not work yet.* ![Screenshot 2025-05-11 at 3.47.19 PM](https://hackmd.io/_uploads/BJr1at0xee.png) ## Creating a User Pool/App Client The demo that I followed for creating the HTML alone is not enough going forward because Cognito has undergone a major UI change sometime in the past year. Therefore, that tutorial along with all AWS documentation and Chat GPT give outdated directions. You used to create a User Pool and then an App Client after. There were a lot of steps because there was a lot more customizability. However, with the current interface you create the User Pool and App Client simultaneously. **I could not find documentation on this updated process anywhere online, so that is what this tutorial is for.** 1. Go to [Amazon Cognito Home Page](https://us-east-1.console.aws.amazon.com/cognito/v2/home?region=us-east-1) 2. Select "User Pools" and then "Create user pool" 3. Select "Traditional web application" under Application Type and name the application whatever you'd like. ![Screenshot 2025-05-11 at 3.11.37 PM](https://hackmd.io/_uploads/HkdY4KCegg.png) 4. Check "Username" for a sign-in identifier, and check whichever attributes you would like to require for sign-up under the drop-down. I selected email and name just to make the demo process quicker. ![Screenshot 2025-05-11 at 3.13.09 PM](https://hackmd.io/_uploads/SJmySYAlll.png) *Note: If you select phone number under required attributes, Cognito will automatically use SMS for user verification. You must configure an IAM role for Amazon SMS integration before you can use SMS for MFA, so I recommend for demo purposes to just stick to email. **If you want to keep phone number required but use email verification, you must make a change in settings** (I will show this process later)* 5. Add *http://localhost:8000/logged_in.html* as your Return URL and click Create user directory. This will take you to the logged_in screen that we created using HTML. ![Screenshot 2025-05-11 at 3.21.47 PM](https://hackmd.io/_uploads/SJP1PKRgee.png) 6. Click "View login page" to see your login screen! ![Screenshot 2025-05-11 at 3.54.23 PM](https://hackmd.io/_uploads/BJRKCFCeel.png) ![Screenshot 2025-05-11 at 3.56.25 PM](https://hackmd.io/_uploads/r1lD-1qAlle.png) 7. We need to make some changes in settings before we sign up. - Back on the Cognito page, select "User pools" and then select the user pool you just created. On the left sidebar under "Applications", click "App clients" and select the one you created. Scroll down and go to Login pages. ![Screenshot 2025-05-11 at 4.03.32 PM](https://hackmd.io/_uploads/rkHhx5Axxl.png) Then select edit and add a signout url. Add the same url as the callback, but change logged_in to logged_out so that it goes to that page. ![Screenshot 2025-05-11 at 4.05.06 PM](https://hackmd.io/_uploads/SyyGZcAllx.png) Scroll down and select save changes. ***If you added phone number** as a required attribute, here is where you need to make changes in settings so that you can use email for verification. If you did not add phone number, skip this and go to the next section* - Under "Authentication" on the left sidebar, click "Sign up". Under "Attribute verification and user account confirmation" at the very top, click "Edit". Under "Attributes to verify", select "Send email message, verify email address" and save your changes. This will make sure that you can successfully signup. ![Screenshot 2025-05-11 at 4.19.14 PM](https://hackmd.io/_uploads/rygDNcAggg.png) ## Testing Login/Signup 1. Go back to the login page tab, and sign up to create a user, and then sign in. *Remember, you will have to verify users using verification so you must provide an email that you have access to receive a code from.* Do not worry about getting an error like this after logging in: ![Screenshot 2025-05-11 at 4.09.17 PM](https://hackmd.io/_uploads/rJi-z9Rlxx.png) Remember that we are not on our local host right now, so it makes sense that our browser cannot access the logged_in.html page. If you get this error, this means that you did successfully login! 2. Go back to the Cognito page, and click "Users" on the left sidebar under "User Management". You should now be able to see the user that you successfully created! You can see my username, email address, and that I successfully verified my email. ![Screenshot 2025-05-11 at 4.11.54 PM](https://hackmd.io/_uploads/HJvsf5Cgxe.png) You can see that you cannot access a user's password. This is an added benefit of Amazon Cognito. There is no reason for us as the developers to have access to passwords, this just creates additional vulnerabilities. Letting Amazon take care of the security and UI makes a login/user database so much easier to manage and less time consuming to create. ## Finishing HMTL Site 1. We need to go back to the main page of the login/signup so that we can copy that link and put it in our .html files. Either go back to your App clients page and View the login page again, or click the back arrow on the same login tab you have open until you see this page:![Screenshot 2025-05-11 at 4.26.05 PM](https://hackmd.io/_uploads/H1qgUqRgxl.png) 2. Copy that link, and go back to VSCode and paste it in replace of the # in the href for index.html and logged_out.html. This is the real link that will actually take us to the main login page. They should now look like this (remember to use your own link and not mine): **index.html:** ``` <body> <h3>Welcome to my Website</h3> <p><a href ="https://us-east-1jkwym47uw.auth.us-east-1.amazoncognito.com/login?client_id=6ld3aqgn06utqr231rnpegjsuh&response_type=code&scope=email+openid+phone&redirect_uri=http%3A%2F%2Flocalhost%3A8000%2Flogged_in.html">Register or Login</a></p> </body> ``` **logged_out.html:** ``` <body> <h2>You are logged out</h2> <p><a href ="https://us-east-1jkwym47uw.auth.us-east-1.amazoncognito.com/login?client_id=6ld3aqgn06utqr231rnpegjsuh&response_type=code&scope=email+openid+phone&redirect_uri=http%3A%2F%2Flocalhost%3A8000%2Flogged_in.html">Log back in</a></p> </body> ``` 3. For the # in the href of logged_in.html, we need to make some changes because we want to direct the user to the logout page instead of the login page. Here is an example link: `https://us-east-1jkwym47uw.auth.us-east-1.amazoncognito.com/login?client_id=6ld3aqgn06utqr231rnpegjsuh&response_type=code&scope=email+openid+phone&redirect_uri=http%3A%2F%2Flocalhost%3A8000%2Flogged_in.html` First, we will change anywhere it says or refers to login/redirect from `login` to `logout`. 1. Change right after the `amazoncognito.com/` from `login` to `logout`. 2. Change `redirect_uri` to `logout_uri` 3. Change `logged_in.html` at the very end to `logged_out.hmtl`. Now, our link looks like this: `https://us-east-1jkwym47uw.auth.us-east-1.amazoncognito.com/logout?client_id=6ld3aqgn06utqr231rnpegjsuh&response_type=code&scope=email+openid+phone&logout_uri=http%3A%2F%2Flocalhost%3A8000%2Flogged_out.html` Finally, we will get rid of this portion because we do not need the response type or scope: `response_type=code&scope=email+openid+phone&` Our final link should now look like this, and can replace the # in the href for logged_in.html: ``` https://us-east-1jkwym47uw.auth.us-east-1.amazoncognito.com/logout?client_id=6ld3aqgn06utqr231rnpegjsuh&logout_uri=http%3A%2F%2Flocalhost%3A8000%2Flogged_out.html` ``` **logged_in.html:** ``` <body> <h1>Congratulations!</h1> <p>You are now logged in.</p> <a href="https://us-east-1jkwym47uw.auth.us-east-1.amazoncognito.com/logout?client_id=6ld3aqgn06utqr231rnpegjsuh&logout_uri=http%3A%2F%2Flocalhost%3A8000%2Flogged_out.html">Log out</a> </body> ``` Restart your server by using command+C or control+C to kill it, then rerunning the `python3 -m http.server` command and going back to your localhost:8000 link in your browser. Now, after logging in through the localhost you do not get an error, it takes you to our logged_in page! ![Screenshot 2025-05-11 at 4.58.14 PM](https://hackmd.io/_uploads/rkKcTc0ggx.png) You should now be able to sign up/sign in using your site, and confirm that any users you create exist in your database under Users on the AWS site! ## Added Customization Now that we have a basic implementation working, there is a lot of opportunity for optional added customization! ### Added custom attributes/passwords: Besides the list of attributes that we saw when creating the User Pool like Gender, Name, Birthdate, Address, etc., you can also add custom attributes. This can be anything you want, like favorite color, age, or T-Shirt Size. To do this, on the left sidebar under Authentication go to "Sign-up" ![Screenshot 2025-05-12 at 1.31.27 PM](https://hackmd.io/_uploads/H16KA3kZll.png) Click "Add custom attributes" ![Screenshot 2025-05-12 at 1.32.29 PM](https://hackmd.io/_uploads/SyhTR21Zee.png) Here is an example of adding Age as a custom attribute. I made the type a number and the minimum 18 years old. This could be for some type of account where you have an age limit. Once I save changes, Age will now be a required attribute to sign-up with and all users' ages will be stored in the Cognito database. Also, the default requirements for passwords are pretty rigourous: ** Contains minimum 8 character(s) Contains at least 1 number Contains at least 1 special character Contains at least 1 uppercase letter Contains at least 1 lowercase letter** If you want to edit these, they can easily be customized by going to "Authentincation methods" under Authentication on the left sidebar and scrolling down to "Password policy": ![Screenshot 2025-05-12 at 1.36.49 PM](https://hackmd.io/_uploads/rJaayaJ-ll.png) Select "Edit" and "Custom": ![Screenshot 2025-05-12 at 1.37.37 PM](https://hackmd.io/_uploads/HJRllaJbee.png) You can now change these requirements to whatever you would like! You can also allow **passkeys** for login. This would be like using a finger print or facial recognition. The place to add this is right under "Password policy" on that same page. ### Identity Pools: Depending on your desired implementation, some of your users may have different permissions than others. For example, Drake uses Blackboard for grades/completing assignments. Both professors and students use the same login, but they have different permissions once verified. Professors need to be able to upload grades and assignments, and students need to be able to view their grades and turn in their assignments. This means that there is a separate identity pool for Professors and Students. You can create this in three steps by selecting the Identity pools tab on the main Amazon Cognito Screen: 1. **Configure identity pool trust**: You can select Amazon Cognito here or other platforms like Facebook, Amazon, Google, and Apple. 2. **Configure permissions**: Give each pool an AWS Identity and Access Management (IAM) role that says what they have access to. 3. **Connect identity providers**: This is where you could conncect with other authenticated identity sources like Apple or Google to use their accounts for login. ### MFA Multi-Factor Authentication can be implemented as an added protection for your site. To do this, go to "Sign-in" under the Authentication tab on the left hand sidebar and find "Multi-Factor Authentication". Click "Edit". ![Screenshot 2025-05-12 at 1.40.13 PM](https://hackmd.io/_uploads/HkY5xa1Wel.png) If you toggle MFA to Required or Optional, you have the option to choose which method you would like. The only extra step here is that SMS and Email MFA are charged seperately by Amazon SNS and SES. There is still a free tier, you just have to take the extra step to set that up. With MFA enabled, you also have the option to add Device Tracking. This allows Cognito to store metadata from the devices your app's users have signed in with, and allow the users to have a remembered device. This setup is in the same location as MFA under "Sign-in", just right beneath. ### Cognito UI Design: Cognito has a lot of opportunity for changing their UI. This is nice because you can put as much (creating a custom design from scratch) or little (leaving default design) effort into it as you want. You can add customization by going to "Managed Login" at the bottom of the left sidebar under "Branding". ![Screenshot 2025-05-12 at 12.51.44 PM](https://hackmd.io/_uploads/S1TNHnkZxg.png) Once you are here, you have a few options. You can select that Style ID and edit the colors, features, buttons, alignment, etc. You could also create a new style from scratch. Finally, you could click "Hosted UI (classic)" on the top and this will let you download a CSS file that you can edit and re-upload to change the style. I think it is the most simple to just edit the current style, so I will show some of those options here: Click on the Style ID ![Screenshot 2025-05-12 at 12.53.50 PM](https://hackmd.io/_uploads/r1ohBnyZel.png) Now click "Edit in branding editor" ![Screenshot 2025-05-12 at 12.54.32 PM](https://hackmd.io/_uploads/HyryInJbll.png) This shows some options on the right hand side. You can scroll down to access even more features to change. Here is what my login looks like after I added a logo, changed the background, and changed the color theme for the buttons: ![Screenshot 2025-05-12 at 1.19.26 PM](https://hackmd.io/_uploads/Hk92ihJbll.png) ### Improve your Website The HTML website that I set up was very simple because it was just a demo. In a real Project, you could add whatever functions you want after the user has logged in. You can do this by adding additional .html files and potentially making identity pools if your site has additional AWS features. As far as website design goes, this is really boring. If you wanted to add CSS, the site could look a lot better! I asked Chat-GPT to give me some code to make my site look better, and here is what it came up with: It added a style.css file: ``` /* Reset default margins and padding */ body { margin: 0; padding: 0; font-family: 'Segoe UI', sans-serif; background: linear-gradient(135deg, #f0f4ff, #dbeafe); color: #333; display: flex; height: 100vh; align-items: center; justify-content: center; } .container { text-align: center; background-color: white; padding: 2rem 3rem; border-radius: 1rem; box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1); } h1, h2, h3 { margin-bottom: 1rem; } .button { display: inline-block; background-color: #2563eb; color: white; padding: 0.75rem 1.5rem; border-radius: 8px; text-decoration: none; font-weight: bold; transition: background-color 0.3s ease; } .button:hover { background-color: #1e40af; } ``` and applied this class to the other three .html files. It also added some buttons and containers. Here is the finished product: ![Screenshot 2025-05-12 at 1.57.20 PM](https://hackmd.io/_uploads/rkaq4TJWlx.png) ![Screenshot 2025-05-12 at 1.57.36 PM](https://hackmd.io/_uploads/BJhoVa1Zxx.png) ![Screenshot 2025-05-12 at 1.57.53 PM](https://hackmd.io/_uploads/ByRnETk-lx.png) ![Screenshot 2025-05-12 at 1.58.02 PM](https://hackmd.io/_uploads/HJv6Ep1-xg.png) # Reflection After completing this demo and researching Amazon Cognito, this is what I found: ## Advantages: **I was extremely impressed with Amazon Cognito.** I found that it was so much simpler to use this than create my own login. I know this because for Project 1, I created a login/signup page from scratch that connected to an AWS DynamoDB Database. I had to build the database, connect it to my coding environment using Boto3, and create the UI from scratch. This took way more time and effort, was completely insecure, had a worse design, and had *way* less capabilities. Here are a few of the features that I could never have accomplished building from scratch that Cognito made easy: 1. **Logging In**: This was great because my browser remembers my passwords, so I could just use my fingerprint to login. I could also use the "Strong Password Generator" that my browser offered to make logging in even easier and reset your password if you forgot it. Also, the ability to use third party companies like Apple, Faceboook, or Google to login is something I could have never accomplished building it from scratch. 2. **Security**: There was zero security when I built it from scratch. Cognito uses verification, MFA, password restrictions, and hides the passwords from the database for added security. Personally, I feel *way* more comfortable with AWS in charge of this because they have the resources to gurantee security. 3. **Design:** While I could have taken *hours* to use CSS to craft a perfect design for my login, Cognito does it for you and it looks *real*. You can tell from the design that it is professional grade and looks identical to logins used on the biggest sites. It also allows for customizability without using any CSS if you prefer, which makes it super easy to make it look exactly how you'd like. I also felt that the **pricing was extremely affordable.** I feel that the majority of industry use cases could even fit under the free tier because 10,000 different users per month is *a lot*. I know that anything I build in the future would likely fit under this free tier, and the price is super cheap for any additional users. I think using Amazon Cognito is a no brainer, and I would definitely reccommend it to anyone developing a website. However, there are a few disadvantages that I found. ## Disadvantages: As I mentioned a bit at the beginning, I had a very hard time implementing Cognito with FlaskApp. Here are the three main issues I found with Amazon Cognito: 1. **Debugging is Hard:** I found that debugging was very difficult, and my Errors were extremely vague (HTTP 403 or Invalid Request/Permissions). Even with added debugging statements within my own code, this never triggered and I couldn't seem to find any documentation/help online about these errors (this leads to my next issue) 2. **Documentation is Outdated**: As I discussed previously, all documentation from AWS itself, ChatGPT, and other online tutorials were not updated to the new UI. The entire process of creating a user pool/app was changed and no one that I could find seems to have explained how to use this yet. This led to a lot of trial and error on my part with basically no help. I hope that this tutorial did a good job of explaining how to get a simple HTML site going with Cognito, but I still would like to be able to implement the code that AWS provided in the Quick Setup Guide and I still do not know how to do this. 3. **Overlapping AWS Systems:** It was a little difficult to keep up with all of the AWS features that you had to utilize. Cognito was great, but different aspects of Cognito relied on other AWS services. For example, the ones I touched on for MFA like SES and SNS require a different set-up and follow different pricing. Something I did not touch on but that is also important is that there is no native support for audit logs, user activity tracking, or analytics dashboards. User insights are extremely valuable to developers, and to access these Cognito requires CloudWatch (which again has additional pricing/signup).