Amazon Cognito from AWS is really gaining traction thanks to its array of features, which make it easy to add sign-in/sign-up and access control features to your web application. But is it really all roses? How practical is it and how to fully benefit from it? Learn all of that and more from this practical Amazon Cognito tutorial.

Almost every application needs to authorize, authenticate and process user data. There are a lot of ways to go about it, some of them good, some of them less so. 

For nearly a year, my team and I have been working on an application that uses an AWS solution, Amazon Cognito, which really helped us out in some ways, and made us lose our minds in others.

In this article, I’m going to share my experience in this practical Amazon Cognito tutorial.

What is Amazon Cognito?

AWS describes Cognito as a product that lets you add user sign-up, sign-in, and access control to your applications quickly and easily. It scales to millions of users and supports sign-in with social identity providers. Sounds like everything you might need for your application. But it actually can do a lot more!

Notable features

Sign-in with identity providers

Cognito supports sign-in with social identity providers, such as Apple, Facebook, Google, and Amazon, and enterprise identity providers via SAML 2.0 and OpenID Connect.

User storage

Cognito can store up to 40 million users! And thanks to the AWS pay-as-you-go approach for pricing, you only pay for users that sign in each month.

There’s also a free tier that includes the first 50,000 users signed in using User Pool credentials or social identity providers.

This means that a lot of small apps, and apps that are in development, won’t even leave the free tier!

Advanced security features

Cognito has security features that protect your users and their accounts from danger.

Cognito can automatically detect unusual sign-in activity, such as sign-in attempts from new locations and devices. It assigns a risk score to the activity and lets you choose to either prompt users for additional verification or straight-up block the sign-in request. It can also notify users of suspicious login attempts.

Amazon Cognito settings

Cognito can also detect credentials that were compromised, prompting users to change their passwords.

Messaging

Cognito can send email messages to verify user email addresses, telling them that they’ve been invited and notifying them of suspicious sign-in attempts to their accounts.

Cognito also sends SMS messages used for Multi-Factor Authentication.

In-built UI

Cognito has an in-built, customizable UI that can be used by users  to sign up and sign in. This allows you to quickly develop a basic application or even skip the process of building those elements altogether.

Custom triggers

Cognito allows you to make advanced customization using AWS Lambda functions. For example, you can have your Lambda trigger when a user tries to sign-up to perform some custom validation and accept or deny the sign-up request. More on that later…

Okay, that’s a lot of very useful features!

And there are a lot more! So, where’s the catch?

Are there any downsides?

Unfortunately, nothing is perfect. For every notable feature, there are hidden catches and problems just waiting to ruin your day. 

Messaging

In-built messaging is great until you realize that it’s very limited. Amazon Cognito can only send up to 50 emails per day, making it virtually useless even for testing purposes. You need to configure and attach your own Amazon Simple Email Service (SES) to increase the limit. This doesn’t help with the character limit, which is 20,000 and cannot be overwritten. 

In addition, Cognito doesn’t give access to the authentication codes it sends. It provides strings that need to appear in your messages and replaces them afterward. 

I also complained about not being able to override or capture codes for testing purposes. It requires a custom solution for capturing emails and SMS messages. But this is no longer the case. There IS a feature that gives access to the codes themselves and allows you to send them to wherever you want! It was added to the documentation very recently, even though it has existed since November 2020! This brings us to our next point…

Amazon Cognito’s documentation

Documentation is probably the most important thing in a developer’s life. It tells us how to do things we want to do and explains how and why they work. 

Cognito’s documentation isn’t terrible, but it’s also not great. Sometimes it’s missing crucial information or is outdated. Examples often lack relevant steps and code could be better. It often gives basic information about the existence of a feature and its purpose. But most of the time you’re left on your own to figure out how it works and how to properly use it.

Communicating with Cognito directly

Cognito is designed to be talked to directly, so you don’t need to design and build an API to handle that, which is a huge timesaver. However, it gives no control over what actions are and aren’t allowed. Users can take any action on their account, from changing the password and updating their details, to straight-up just deleting their account. And you cannot stop it! Triggers can help customize some of those, but most of the time users can do whatever they want.

Backups

Cognito doesn’t provide any backup tools. If you want to backup your users, you need to do it yourself.

While Cognito can import users from a .csv file, or migrate them from another source, it cannot do that with the user’s password. So if you ever, for any reason, want to move your users or destroy your user pool, prepare for password resets.

Custom attributes

If you think that it’s not that easy to destroy your pool, then you’re right. But it’s not that hard either. Cognito can store custom attributes defined by you, in case you want to keep some extra information related to the user account. However, those cannot be modified after you create the user pool.

Customization with triggers

Amazon Cognito triggers are a way to customize some user pool operations using AWS Lambda. In my opinion, they are really useful and really fun to develop.

There are multiple triggers that can be used in many ways. I’ll spare you listing all of them, but I’ll mention the ones we use.

Custom Message Trigger

Very useful for translating and personalizing messages. Most message types accept only the MFA or confirmation code. This trigger allows you to add custom things, such as names, to messages. We also use it to translate messages.

The important thing to remember is that it’s impossible not to send a message. If the lambda doesn’t respond in time or throws an error, Cognito defaults to the message set in the user pool itself.

Pre Token Generation

This one is a great feature when you want to add extra information to the token generated for the user when authenticating. Saves us a bunch of time on every request, because we can put some data in the token, instead of fetching it from the database on every request. Take extra care when deploying it, though. Unlike the custom message trigger, this one doesn’t have a fallback mechanism. If lambda throws an error, tokens are not generated and users are unable to log in.

Remember to catch your errors. Since Cognito expects lambda to return the event that it has received, uncaught errors are sent back to the user in the form of a pleasant message “Invalid version. Version should be 1”

Post Authentication

We use it to pass information about logins to another service. Since it happens after authentication succeeds, but before the token is generated, it suffers from the same issues as the PreTokenGeneration trigger does.

Custom Auth Challenge

I had some fun figuring out how this one works. We tried to use a custom authentication flow to change users’ phone numbers if they put in incorrect ones while signing up. The entire custom challenge flow consists of 3 triggers:

  1. Define Auth Challenge – allows you to request auth challenges to the users and accept or fail the auth challenge.
  2. Create Auth Challenge – runs when a custom challenge is requested. You can use it to create the challenge and return the relevant data to the user.
  3. Verify Auth Challenge Response – verifies if the user’s answer to the challenge was correct

It was almost a perfect solution, but there’s always a catch. Cognito has many possible challenges. One of them is password verification which is necessary to make sure that the user actually gave us their correct password. However, when the user pool has enforced MFA, Cognito treats password verification and SMS MFA as one challenge. It means that even if you don’t request the MFA challenge, Cognito will still enforce it. That one ruined my day. 

Custom Senders 

New triggers that were recently added to the documentation and are still hidden from the AWS console. They allow you to completely override email and SMS sending mechanisms. I’m looking forward to trying them out. Hopefully, they will be fully integrated into the console and serverless soon. They might be the key to solving our SMS MFA automated tests issues, possibly even resetting users’ phone numbers.

Amazon Cognito tutorial – final thoughts

In my opinion, Cognito is a great tool, with a lot of awesome functionalities that will suit your needs, as long as your design is aligned with what AWS has in mind. Even though sometimes it makes me want to pull my hair out in frustration, it is definitely a very useful tool that helps us develop our app faster and keep its users safe and secure.

I would recommend giving it a try if you’re looking for a solution like that, especially if you use other AWS services and need to add user authentication to them. Make sure it can do what you need it to do before committing to avoid the struggles!

Leave a Reply