Authentication is the process of determining the identity of an entity, to verify that they are who they say they are. Cognito uses JSON Web Tokens (JWT) which I’ve covered in this previous blog as a standard for representing claims securely between two parties, where a claim is a name-value pair which represents information about the subject, that the server/service holds to be true.
We are going to use Amazon’s Cognito service to manage the user authentication to the REST API. AWS Cognito service provides user sign-up, sign-in and access control and Cognito’s User Pools provide a secure directory service, which can scale to enable you to manage millions of users.
The diagram (right) shows the steps a user must take, in order to be able to access the protected REST API.
As the REST API is protected by access control, the user first needs to obtain a valid JWT. The first step of this process is for the user to login to Cognito using their username and password.
Cognito then verifies that the user is who they say they are, by checking that the username and password provided match what’s in the User Pool.
Once the user authentication has been validated by Cognito, it generates and signs 3 separate JWT tokens:
– an ID Token which contains claims about the identity of the authenticated user such as name, email, and phone_number.
– an Access Token which contains scopes and groups and is used to grant access to authorized resources.
– a Refresh Token contains the information necessary to obtain a new ID or access token.
In Cognito you are able to define the claims that you want the JWT to contain.
The next step for the user is to make the REST API HTTP request to the Gateway API service, which can be hosted on a different domain, passing the JWT Access Token along as part of the header of the request. The Gateway API service has a lot of different features, however at its core it is used to route requests to a defined backend. In this case it will be the test Lambda function that we’ve set up.
The API Gateway has been configured to use a specified Cognito User Pool to handle the authorization, as you can see in the image below.
When a request is received, the API Gateway first checks that the request contains the ‘authorization’ header and then unpacks the JWT Access Token by decoding its contents (excluding the preceding ‘Bearer ’ string) from Base64 to two JSON strings and a signature.
The API Gateway next retrieves the Cognito User Pool’s public key. Amazon Cognito generates RSA key pairs for each user pool, and it’s that private key that is used to sign the JWT token when it’s created. The public keys are made available at an address:
https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json.
If the JWT is valid then the request is allowed to proceed to the next stage.
The API Gateway passes the request on to the configured backend. In this case it’s our simple Lambda function:
The response from the REST API is then passed back to the API Gateway.
As the final stage, the REST API response is sent back to the requesting client.
We hope you’ve found this blog on how to apply access control to your REST API using AWS’s Cognito, API Gateway and Lambda Services useful to ou and your teams. Please do reshare this content or if you have any further questions on the steps outlined above, please get in touch.