In this set of posts I’ll write about using the AWS Cognito service to provide user management for a simple application stack consisting of a React UI served up by a Node.js instance and a backend REST API, also implemented using Node.js but in separate instance.

In our example application, the AWS Cognito service will be used to provide the following functionality:

UI content for user sign-in and sign-up (which we will customise)

Backend OAuth implementation for user authentication and token generation

Maintain a registry of users, including secure storage of profile information such as names and email addresses

Creating a user pool

To get started we create a user pool. A user pool is the container in which AWS Cognito uses to hold and manage all the user identities used by your application. Find the AWS Cognito service, create a new user pool and give it a name. We also need to create an app client for the user pool, so our UI application can interact with the user pool. Since the UI application we’re going to be using a JavaScript based UI (React) for the front end, we also need to uncheck the generate client secret option, as this is not supported for JavaScript clients.

Review the user pool settings, which should look similar to the following:

Reviewing user pool configuration

AWS Cognito provides built-in UI pages to handle user sign-in, sign-up etc. These can be customised or your can roll your own.

Configuring the application integration

Now that we have a user pool created, we need to configure the application integration for it. This will allow us to control various aspects of the application using this user pool, such as the domain name used for authentication, the URL callback used after authentication has taken place, as well as customisation to the initial sign-in / sign-up UI.

For this example application I’m going to be using the domain cognito-demo.arronharden.com for the example UI application and auth-cognito-demo.arronharden.com for the AWS Cognito endpoints.

Domain name

By default AWS Cognito will use a generated subdomain under the amazoncognito.com root. To avoid exposing this domain to your end users you’re going to want to change this to use the domain name of your own application. In order to do this you’ll need to be able to do the following:

Create or import the SSL certificates for the domain in AWS Certificate Manager. See my other post Using LetsEncrypt SSL certificates in AWS Certificate Manager for how I created and imported a LetsEncrypt wildcard certificate for my domain.

Be able to create a DNS CNAME record for your domain to point to the AWS Cognito target associated with your user pool.

I’ve configured this user pool to use the domain auth-cognito-demo.arronharden.com and created a DNS CNAME record for it pointing to d47h50fumb0wo.cloudfront.net.

Specifying the domain for the user pool application integration

Resource server

Since we’re going to create a simple backend REST API service, we need to create a resource server for the application integration. We set the identifier to match the URL of the backend REST API domain, https://cognito-demo-api.arronharden.com, and define a custom scope called hello-world.all which the UI authentication flow can grant to users.

Specifying the backend REST API resource server

App client settings

Now we have the domain and resource service configured, we can carry on and configure the app client which was defined when the user pool was first created. We set the callback and sign out URLs to match our UI application URL, https://cognito-demo.arronharden.com, noting that the for callback we have the additional path /callback so the UI application can process a successful sign in. For the OAuth flows we select authorization code grant and implicit grant. The custom scope hello-world.all created as part of our resource server is also available, and we want to select that too.

For local development purposes, it can useful to also add a localhost callback URL, for example, http://localhost:3000/, so you can still make use the usual auth flow, but it will launch into your locally running UI application, rather than the real one. Remember not to include localhost callbacks for production usage, however.

Specifying the app client settings

Testing the sign up / sign in UI

Now that the application integration has been configured we can go ahead and test the authentication UI flow. The login URL for the example uses the domain we configured and for query parameters has the app client ID (shown in app client settings) along with the callback URL we defined. The full URL for this example is https://auth-cognito-demo.arronharden.com/login?response_type=code&client_id=4tnp4k64d5v4ah9dud3pj1kbs0&redirect_uri=https://cognito-demo.arronharden.com/callback.

Going ahead and trying this URL shows the default AWS Cognito authentication UI.

Default AWS Cognito authentication UI

As this is a new user pool I can go ahead and go through the sign up flow which will create a new user and send a email with the verification code before allowing the user into the system.

Creating a new user

Entering the verification code from the email

Since there is no UI application created yet the final redirect to my app integration callback URL https://cognito-demo.arronharden.com/callback hits a dead end, but that’s expected at this stage.

As a final verification I can now also see that the user arron has been created in the user pool.

User has been created in the user pool

So far we haven’t written any code, but yet we have a powerful and secure user management service and UI ready to be utilised by our UI and backend API services. In the next part I’ll explore the integration with a UI application, showing how to go through authentication flow and how to customise the sign in / sign up flows.