AWS Cognito and IAM for Front-End Developers
Tags: aws, javascript, webdev, cloud
Published: 2022-09-16 03:12:26


Whenever you build a web application, you'll often need to provision accounts for your users. By _users_, I'm specifically referring to _customers_ who interact with your services via your JavaScript/TypeScript frontend.

Managing these user accounts comes with plenty of challenges. Not only will you need to persist user profiles, you'll need to figure out how users can be organized into groups, how to store credentials, what kind of auth mechanisms would be suitable, and so on. 

If you're a front-end developer who mainly cares about building enjoyable web experiences, these concerns might seem tedious to deal with. Fortunately, [AWS Cognito](https://docs.aws.amazon.com/cognito/latest/developerguide/what-is-amazon-cognito.html) handles them for you.

In my [previous blog post](https://yao.page/posts/identity-and-access-management-aws/), I covered some basic concepts around [Identity and Access Management (IAM)](https://aws.amazon.com/iam/). Now, I'd like to build on these concepts by explaining how front-end developers can easily use AWS' Cognito and IAM services to set up authentication and authorization for customer-facing applications.

## AWS Cognito

As mentioned, AWS Cognito handles all the nasty user management work. When using Cognito, you really just need to be familiar with two offerings: __User pools__ and __Identity pools__.

To pull a quote from the Cognito console: 

![A summary of user pools and identity pools](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ms4mqzg7uz8zadpc5s9.png)

> User pools are user directories that provide sign-up and sign-in options for your app users. Identity pools provide AWS credentials to grant your users access to other AWS services.

### User Pools

The term "user pool" is an intuitive one, as it refers to a collection of users (which can be organized into groups).

Cognito provides plenty of features for customizing how this collections of users can be managed. Amongst other things, you can:
- [Enable multi-factor authentication](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-mfa.html)
- [Set up federation with identity providers](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-configuring-federation-with-social-idp.html) such as Google or Facebook
- [Run customized logic](https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-identity-pools-working-with-aws-lambda-triggers.html) as users progress through their auth-related user journeys (e.g. signing up, signing in).

When a user from your user pool logs into your application successfully, they'll have access to an [ID (JWT) token from Cognito](https://docs.amplify.aws/lib/auth/overview/q/platform/js/#accessing-aws-services). This token can be used to obtain a set of AWS credentials corresponding to a specific [IAM role](https://yao.page/posts/identity-and-access-management-aws/#roles). At this point, you might be wondering: How do we relate Cognito users to IAM identities at all? 

### Identity Pools

This is where identity pools come in.

{% embed https://youtu.be/tAUmz94O2Qo %}

Identity pools are a bit trickier to understand. The identities we're dealing with _are_ IAM identities, which means their settings (e.g. permission policies) are defined in IAM, not Cognito.

I prefer to think of an identity pool as a __collection of _associations_ between IAM roles and Cognito user pools__. For example, given a user pool `MyUserPool`, we may want to define an identity pool which assigns one IAM role (e.g. `MyAuthenticatedRole`) for users who are authenticated and another IAM role (e.g. `MyUnauthenticatedRole`) for users who are not.

In other words, these identity pools specify the relationships between user pools and IAM roles. As such, Cognito users are able to [exchange Cognito tokens for AWS credentials](https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-integrating-user-pools-with-identity-pools.html). Front-end clients [receive these credentials from STS](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html), which allows Cognito users to interact with AWS services. 

## In Practice

The steps for getting started with Cognito and IAM are relatively straightforward. On your JavaScript/TypeScript frontend, I recommend using the [Amplify SDK](https://docs.amplify.aws/lib/q/platform/js/), which supports many common authentication and authorization use cases.

### AWS Console TODOs

On the AWS Console, you'll have to:

- Create a Cognito user pool with an app client representing your front-end web application.
- Create a Cognito identity pool with roles for authenticated and unauthenticated users. As you create the identity pool, be sure to link it to your user pool and app client by listing Cognito as an  __Authentication provider__. Also, ensure your authenticated and unauthenticated roles have the necessary IAM policies in place for them to interact with your AWS services, such as [API Gateway](https://aws.amazon.com/api-gateway/) and [S3](https://aws.amazon.com/s3/).

### Front-End Application Code TODOs

In your front-end application code, you'll need to:

- Store the region, user pool, identity pool id, and app client id in a configuration object (e.g. `config`).
- Initialize Amplify with this config object (e.g. `Amplify.configure(config)`).
- Use Amplify's `Auth` module for your auth-related operations. For example, you can simply invoke `Amplify.Auth.signUp(...)` to register a user and add them to your user pool.
- Use Amplify's other modules for interacting with other services. For example, you can use `Amplify.API` to speak with your API Gateway endpoints.

One thing worth calling out with Amplify's `API` module is that it handles a lot of the IAM-based authorization work for you. 

Under the hood, when you invoke a method such as `Amplify.API.post(...)`, the module derives temporary AWS credentials corresponding to the appropriate role (e.g. `MyAuthenticatedRole`). These credentials are used to sign the frontend request payload before sending it to API Gateway. See [this article on SigV4](https://docs.aws.amazon.com/general/latest/gr/signing_aws_api_requests.html) for details on the signing process.

For an overview of what the architecture I've described looks like, check out [this section from an AWS Identity Workshop](https://catalog.us-east-1.prod.workshops.aws/workshops/bc60f0b2-991f-4df9-933c-234a67e75179/en-US/module-2/opt-exts).


## Wrapping Up

Note that using Cognito with IAM is not strictly necessary. For example, you can set up your endpoints on API Gateway to [directly rely on Cognito user pools for authorization](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-integrate-with-cognito.html). Personally, I prefer the IAM-based approach, because it aligns "how Cognito users interact with APIs" with "how AWS services generally interact with each other".

I'm constantly impressed by how much AWS is able to abstract out these software building blocks to help developers scaffold their applications quickly. For anyone looking to get their hands dirty with the tools covered, here are some useful references:

- A Beginner's Guide to Cognito from [one of my favorite channels](https://www.youtube.com/c/BeABetterDev): {% embed https://youtu.be/QEGo6ZoN-ao %}

- [Workshop: Using Amazon Cognito for Serverless Apps](https://catalog.us-east-1.prod.workshops.aws/workshops/bc60f0b2-991f-4df9-933c-234a67e75179/en-US)
- [Building an application with AWS Amplify, Amazon Cognito, and an OpenID Connect Identity Provider](https://aws.amazon.com/blogs/mobile/building-an-application-with-aws-amplify-amazon-cognito-and-an-openid-connect-identity-provider/)
- [Identity and Access Management for Amplify](https://docs.aws.amazon.com/amplify/latest/userguide/security-iam.html)