In Part 1 of this tutorial series we configured AWS Cognito User Pools for user management and authentication. And In Part 2 we created four (4) Lambda functions required to demonstrate SignUp, SignIn, RefreshToken and accessing Private API. In this final part we will create four (4) APIs -
- Sign Up API
- Sign In API
- Refresh Token API
- Private API
using API Gateway and mapped them with cognito user pool and respective Lambda functions. Let’s start one by one -
Creating Sign Up API
Login to your AWS console, browse API Gateway section under Services Menu from top. Click Create API, select REST protocol, select New API, under settings give your API a name, description and select Regional as Endpoint Type. Then click Create API.
Expand Actions dropdown, click Create Resource.
Give your resource a name and path e.g. signup, check Enable API Gateway CORS and then click Create Resource.
You’ll be redirected to a screen like below.
Select /signup, expand Actions, click Create Method.
Select POST as a method from dropdown and click tick mark right to this.
You’ll be redirected to the configuration page for this endpoint. Look for signUpWithCognito Lambda function that we created in our last tutorial to map that with this signup endpoint. And then click Save.
A prompt will appear with titled “Add Permission to Lambda Function”. Click OK. You’ll be redirected to another setup page like below.
We don’t want to write validation logic in our lambda function which will only deal with business logic. We will validate an incoming client request in API Gateway before we forward the request to respective lambda function. If validation fails API Gateway will return validation failed response and your lambda won’t be invoked at all thus saving cost.
To accomplish this click Models in left sidebar menu. Give that model a name e.g. SignUpValidationModel, write application/json in Content type field, give this model a description on what it does. Under Model Schema section paste below code snippet. And then click Create model. Your SignUpValidation Model will be created then. Here I used sample validation logic, however you are free to explore and write your own validation logic as required.
Upon clicking Create model, click Resources from left sidebar menu, select POST method under signup, click Method Request. Select Validate body as Request Validator, expand Request Body section, click add model, under Content type write application/json and select SignUpValidationModel as Model name. Check both tick mark right to Request Validator and Model Name to save these settings. And then back to previous page by clicking Method Execution link in top.
Click Test. Scroll down to bottom and then paste below JSON as test signup data under Request Body and then again click Test.
“name”: “John Doe”,
Scroll to right and everything is okay you’ll find below response. What Test did is — it forwarded your given request body to signUpWithCognito Lambda function as configured earlier, lambda code gets executed successfully, create a new cognito user in user pool and return this response. The Sign Up request was successful and a new user has been added to the user pool.
Creating Sign In API
Create a new model e.g. SignInValidationModel to validate incoming signin data. Use below code snippet as validation model logic (for example) -
Click Resources from left sidebar Serverless APIs section or whatever name you gave to your API. Click / , click Create Resource. Give that a name signin and follow the similar way to create a POST endpoint, configure and mapped it with signInWithCognito lambda and test it. Use below request body to test -
If everything configured correctly upon clicking test you’ll get a response like below
So far we are done with Sign Up and Sign In API and your API dashboard will be something like this -
Creating Private API
Click / under Resources, click Actions, click Create Resource, give your resource a name and path e.g. profile and then click Create Resource.
Your profile resource will be created then. Create a GET method under profile. Map it with privateLambdaFunction and leave everything as default. Click Save.
Click Authorizers in left sidebar menu to create a new authorizer to protect our private lambda function. Give that authorizer a name e.g. ServerlessPrivateAPIsAuthorizer, select Cognito as type as we are going to use cognito user pool to authorize the incoming request from client using provided IdToken that user received in response upon successful Sign In call. Select our user pool that we created in part 1 of this tutorial, write Authorization as Token Source, leave rest as default and then click Create.
What this authorizers will do is that — it will look for Authorization header in incoming request for valid IdToken to access the private lambda function, crosscheck it with cognito user pools. If the IdToken is valid then API Gateway will forward the request to respective lambda function. Hence it protects our private APIs from being called by unauthorized user.
Again click Resources from left sidebar, select GET method under /profile, click Method Request. Select ServerlessPrivateAPIsAuthorizer as value for Authorization field under settings, click tick mark to save.
Click Method Execution to return to previous page. Click Integration Request, Expand Mapping Templates, select “ When there are no templates defined (recommended)” as value for Request body passthrough. Click “Add mapping template”. Under Content-Type write application/json, click tick icon to save.
Then Click “application/json”, scroll to bottom. In code editor under General template paste below code -
Click Save. What it does is — when a request is received by Method Request from client it will validate the incoming request using cognito authorizer that we set in earlier steps and if validation passed it will forward the request to Integration Request along with authorization data like which user is requesting the resource. We will append these user information along with original user request data and pass it to the lambda function so that it has the user information that it needs to serve the specific user in response to the request. These way we can protect all our private APIs from unauthorized access.
Creating Refresh Token API
By default an IdToken received as response from SignIn call is set to expired after 3600 seconds. Once an IdToken gets expired we need to call a refresh token API to request for a new IdToken against the refresh token. Let’s create our final refresh token API.
Create a new POST method under refresh-token resource, map it to newIdTokenUsingRefreshToken Lambda function that we create in Part 2 of this tutorial series and then click Save.
We are done with all four API creation. Now to make these APIs publicly available with publicly accessible endpoints we need to deploy these API. Click “/” under resources, click “Actions”, click Deploy API. Create a new stage, give that a name and description e.g. beta and then click “Deploy”.
Expand “beta” under “Stages”. Click on each method under each resource i.e. /profile GET, /refresh-token POST, /signin POST, /signup POST to get respective Invoke URLs.
Your API endpoints will be something like this -
Sign In API: POST https://*******.execute-api.ap-*******.amazonaws.com/beta/signin
Sign Up API: POST https://*******.execute-api.ap-*******.amazonaws.com/beta/signup
Private API: GET https://*******.execute-api.ap-*******.amazonaws.com/beta/profile
Refresh Token API: POST https://*******.execute-api.ap-*******.amazonaws.com/beta/refresh-token
Open a REST client e.g. Postman to test all your endpoints and desired response.
You can check my postman collection against these API in below docs where I masked the base URL and other sensitive information. Kindly use your API Gateway generated endpoints to conduct testing these APIs.
I tried to keep it simple without going into much deeper concepts. I suggest you to explore more for in-depth features.
Thanks for your patience while reading this tutorial.