One of the cool API Gateway features is the way it handles access control. Among other options, it can leverage IAM credentials or API keys to authorize your endpoints, but if none of that fits your needs it also has Lambda (formerly Custom) Authorizers, which pretty much lets you set your own rules. However, in certain cases you don’t only need a way of protecting your API, but you also want to let users register in your app, verify their email addresses, reset passwords or allow them to login and register using social providers such as Facebook. You could certainly build all those features from the ground up and store your users’ data in a database of your choice, but why would you do that when all you need to do is run
serverless deploy? Cognito User Pools provides that and much more, just by adding some Cloud Formation resources to the
serverless.yml file, your serverless app will have users management capabilities. (Working example here)
What is a Cognito User Pool?
Cognito User Pools is a managed user directory (don’t confuse this with Identity Pools). You can use it as an identity provider, so that anybody can register and sign in to your web/mobile app. It includes all the basic features you’d normally need regarding users’ management, such as email verification or password recovery, but we appreciate the value of Cognito when we notice that things like multi-factor authentication or social sign in can be added with a couple of clicks.
It’s important to note that the outcome of Cognito when a user logs in is a JSON Web Token, not AWS credentials, which means that you can pretty much use it with any API you build. However, if you’re using API Gateway, this task becomes much simpler, as Cognito already has a Lambda Authorizer you can use. Let’s see how we can integrate it in our Serverless app.
Creating a Cognito User Pool in your Serverless service
The first thing we need to create is the User Pool, which is basically the users’ directory. It allows you to configure certain security aspects, such as whether we enable multi-factor authentication or the requirements passwords should meet, the attributes you’d like to store about your users or if you prefer them to sign in using their username, email or phone number. In this case, we’ll let our users register with their email address and will require the password to have a minimum length of 6 characters, including an uppercase and a number. You just need to include the snippet below under the
resources section of your
The user pool is not enough on its own, we also need to create an App Client. The App Client allows applications (mobile, web, server-side, etc.) to issue requests to the Cognito APIs that are normally unauthenticated, such as APIs to register, sign in or recover passwords. We just need to add the resource below:
Using the Hosted UI
Cognito also has a built-in front end that handles sign-up and sign-in, we only have to configure the URL of our app where users should be redirected after logging in or out. Unfortunately, this cannot be done through CloudFormation, so we need to go to the Cognito Dashboard in the AWS Console. Once there and after selecting our User Pool, we have to select App client settings on the sidebar, enter our callback URLs and check Implicit Grant along with all the OAuth scopes, which basically means that we’d like to get JSON Web Token back after the user has authenticated.
Almost there, only one step left! Before you move on, take note of the Client ID that appears on top of the page, because you’re going to need it afterwards. Now go ahead and select Domain name, where you’ll create the domain your users will sign in and register from:
And that’s it! Direct your users to
https://<your_domain>/login?response_type=token&client_id=<your_app_client_id>&redirect_uri=<your_callback_url> and you won’t need to handle sign ins, registrations or password resets. Go ahead and replace the missing pieces in the previous URL with your own Cognito URL, Client ID and Callback URL, paste it into your browser and try it out yourself. After successfully signing in or registering, you’ll be redirected to
https://<your_callback_url>/#id_token=123456789tokens123456789&expires_in=3600&token_type=Bearer, just remember that you’ll have to store the value of
id_token in your front-end app to call the API.
Protecting API Gateway Endpoints
Most of the job is done at this point, but we still need to tell our API to accept incoming requests only if the user has successfully signed in. For that matter, we’ll create a new resource that holds the API Gateway authorizer pointing to the User Pool:
- Fn::GetAtt: [CognitoUserPool, Arn]
Last but not least, we have to attach the newly created authorizer to the endpoints we’d like to protect:
Now, whenever we want to access the
/hiUsers endpoint, we must provide a valid
id_token in the HTTP
Having users management capabilities in your Serverless app and protecting your API is now easier than ever thanks to Cognito User Pools. Hopefully, this post will help you getting everything up and running but, if you find it difficult to set up, you can take a look at a working example in this repo.