AWS Cloud Operations Blog
Configuring machine to machine Authentication with Amazon Cognito and Amazon API Gateway – Part 2
This blog is the second part to a 2 part series on how to secure your Amazon API Gateway with Amazon Cognito, in machine to machine (M2M) communication use cases.
In the previous blog post, we dove deep into the different use cases involving M2M communication and how it contributes to business modernization, and why securing this type of communication is important.
In this post, we will walk you through a step-by-step solution for implementing secure, authentication based, M2M communication in your own environment. Here’s a high-level overview, and an architectural diagram of the solution we will be building.
Fig-1: Architecture
Step A: Client Authentication – The client represents the machine or service that needs to access the protected API. It has credentials, such as a client ID and potentially a client secret, that it uses to authenticate by sending a request to Amazon Cognito.
Step B: Access Token – Amazon Cognito validates the client’s ID and secret to ensure the client is registered and authorized to obtain an access token. After successful authentication, Amazon Cognito issues an access token to the client. This token is a representation of the client’s credentials and permissions to access the API.
Step C: Client Request with Access Token – The client now makes a request to the Amazon API Gateway, including the access token in the request’s authorization header. Amazon API Gateway validates the access token with Amazon Cognito to ensure it is valid and has not expired and grants or denies access based on token validity.
This flow ensures that the client’s credentials are securely passed to the authorization server (Cognito) to obtain a temporary access token. The client then uses this token to access the protected API, without needing to expose its sensitive credentials directly to the API Gateway.
This blog is intended to show how it works at a high-level, so we will use Postman to demonstrate this. In a real-world scenario when it is implemented in a service, postman will not be used. For this demonstration you will send the request with the Client ID and secret to the Authorization endpoint. This will provide a response with the token, and you send the second request with that token to the Amazon API Gateway to get access to the API. In a production application, all of that logic will be managed by the requester and Postman will be out of the picture.
In the next steps we’ll walk you through the steps required to build the solution on AWS using the console.
Implementation
Prerequisites
- AWS Account Setup.
- IAM User with permissions to perform the duties below but applying least-privilege permissions. Please refer to this for policy examples for Amazon Cognito and this for Amazon API Gateway.
- Postman: To demonstrate the high-level functionality of the API authentication flow using Amazon Cognito and Amazon API Gateway.
Step 1: Authorization Server Endpoint set up:
In this step, you will create an Amazon Cognito use pool, create a confidential client and OAuth 2.0 Client credentials grant type which will be used for M2M authentication. Next, you will create a custom resource server with 2 custom scopes – one for read access and one for write access which will be associated with the confidential client to request access to resources when making API requests. This setup ensures that the external client can securely authenticate and obtain access tokens to interact with the protected API, without needing to expose sensitive credentials directly.
1. Sign in to the AWS Management Console and open the Amazon Cognito console
2. In the navigation pane, under Amazon Cognito, choose User Pools.
3. Choose Create user pool (here you have 2 options, or the orange button, or the button in the middle of the screen). We’ll walk you through the wizard’s steps:
In Step 1 select User name
In Step 2, under Multi-factor authentication, select No MFA
In Step 3, leave everything as default
In Step 4, under Email provider, select Send email with Cognito
In Step 5, we setup the app integration:
Enter a name for the user pool, and under Hosted authentication pages, select Use the Cognito Hosted UI for sign-up and sign-in flows. Also, you will need to enter a Cognito domain, that will serve as the authorization endpoint that the client needs.
Fig-2: Integrate your app
You want to create a confidential client for M2M authentication even if the client will be used with APIs or machine clients that reside outside of AWS. Confidential here means it is a client with a secret and to be used by machines as mentioned in the first part of the blog series.
4. Choose Generate a client secret to generate a client credentials grant.
Fig-3: App client configuration
Now you can configure the advanced app client settings. You need to add the client credentials grant, under the OAuth 2.0 grant types. However, as the message indicates “Client credentials grant type is disabled during the creation of the event”. So, go ahead and click through to Next and create the user pool. You can add the client credentials grant later.
In the Step 6, we review the configuration, then select Create user pool.
5. Now we need to create the resource server. A resource server is a representation of the backend server that you will be protecting using access tokens. The client request will be authorized by the Amazon Cognito resource server. We will need to create a scope – a level of access that an app can request to a resource. In an Amazon Cognito access token, the scope is backed up by the trust that you set up with your user pool: a trusted issuer of access tokens with a known digital signature. We’ll walk you through the steps:
A. Select the User pool created in the previous step, and choose the App Integration tab
B. Select Create resource server, enter a Resource server name and identifier.
C. Create two new custom scopes, for read and write as shown below, then select Create resource server.
Fig-4: Resource server configuration
6. In the App Integration section, scroll down to App client list, locate the App client created in a previous step and select the link to open it.
In the Hosted UI section, choose Edit. Here we add the Client credentials grant under the OAuth 2.0 grant types. We also need to add in the Custom scopes. The scope here defines what actions and resources the application is allowed to access. In our case, we have a custom scope which allows the application read and write access. Choose Save changes.
Fig-5: Hosted UI configuration
Step 2: Amazon Cognito Integration with Amazon API Gateway
In this step, we will configure the integration between Amazon API Gateway and Amazon Cognito to secure the API exposure.
1. In the navigation pane, choose Amazon API Gateway.
2. Choose Create API and then choose Build on the Rest API section.
3. Enter a meaningful API name, select regional as the API endpoint type and choose Create API.
Fig-6: Creating a REST API
4. Now, choose Create Resource, and add in a resource name such as /blog. Choose Create Resource.
Fig-7: Creating a resource
5. Select Create method from the right-hand side, select GET from the Method type. Select Mock as the Integration type and choose Create method.
We will now create the response that will help to validate the security of our integration.
To Mock the answer you will need to create a Mapping Template in the integration response. The template will return that Amazon API Gateway was successful to read, and 200 status code.
6. Select the Integration response tab and choose Edit to change the mapping template.
Fig-8: Method execution
7. Expand the Mapping template section to add the following text into the Template body and choose Save.
{
"status": "successful read"
}
Fig-9: Integration response
7. Choose Create method, to create another method under /blog. This time, select POST from the Method type. Select Mock as the Integration type and choose Create method.
Expand the Mapping template section to add the following text into the Template body and choose Save:
{
"status" : "successful write"
}
8. Choose Deploy API in a New stage called Prod.
Fig-10 Deploy API
After the deployment you can check the URL to be invoked from the Invoke URL section of the Stage details:
Fig-11: Invoke URL
Step 3: Testing the API Gateway using Postman
In this step, you will be using Postman API Platform to make requests and test the API Gateway. To do this, enter the invoke URL followed by /blog and this will return a successful read message for a GET method, and a write message for a POST method. In this configuration, the API is not secure because we have no authorization configured.
Fig-12: Postman
To add a security layer, you will add the Amazon Cognito integration piece that we configured in a previous step:
1. In the navigation pane, under Amazon API Gateway, choose Authorizers.
2. Select Create Authorizer and enter a suitable Authorizer name. Change the Authorizer type to Cognito, and select your user pool from the Cognito user pool section. Enter the Token source as Authorization and select Create authorizer.
Fig-13: Create Authorizer
3. Add this authorizer to the 2 methods you created – GET and POST. To do this, select Edit method request, for the GET method and enter blog/read under the Authorization Scopes. Make sure to update the POST method and enter blog/write under the Authorization Scopes.
4. Redeploy the API to the Prod stage to test the new secure API.
When you retest this in Postman, it should give an Unauthorised message and a 401 error. This is because an authorization token is not being sent.
Fig-14: Unauthorised message
5. To address this, include the token in the call. Within Postman, add the Authorization type to OAuth2.0, change the Grant type to Client Credentials and add the Cognito Domain URL. This can be found in the App Integration section of the User pool in the Amazon Cognito console. Make sure to add the /oauth2/token at the end.
The Client ID and Client Secret can be found in the App Integration section of your User pool. Click on the App client list and select your App Client to view it.
Fig-15: App Client
Fig-16: Configuring a new token with the details
6. Scroll down the page and select Get New Access Token.
After successfully authenticating, Postman will show the following message: “authentication complete”.
This functionality of Postman will capture the token that will be used in the Token section to have authorization to call our API.
Fig-17: Successful write
7. Repeat the step mentioned above for the GET method. It will also provide a successful read.
Cleaning up
Deploying this solution in your AWS account will incur costs. To avoid ongoing charges, when you’re done examining the solution, delete the resources that were created, such as the API Gateway resource, and Amazon Cognito user pool.
This is a Mock, how would this work in real life?
This blog is intended to show how it works at a high-level, and hence Postman is used to demonstrate this. In a real-world scenario when it is implemented in a service, postman will not be used. For this demonstration you will send the request with the Client ID and secret to the Authorization endpoint. This will provide a response with the token, and you send the second request with that token to the Amazon API Gateway to get access to the API. In a production application, all of that logic will be managed by the requester and Postman will be out of the picture.
How our solution differs from using AWS App Mesh?
AWS offers a great breadth of services, catering to different use cases, such as AWS App Mesh. App Mesh helps you streamline operations, implement custom traffic routing rules, and configure and standardize the traffic flows between services. While this sounds similar to the solution covered in this blog, there is one caveat – how the network works. AWS App Mesh excels in handling East-West traffic between services, such as internal traffic and auditing. Our solution is for North-South traffic, such as externally originated traffic. Therefore, the solution we’ve walked you through is more suitable than App Mesh for the use case.
Conclusion
If you’re looking to build a secure machine-to-machine (M2M) authentication solution on AWS, go ahead and follow the steps outlined in this post. We’ve walked you through the process of setting up an M2M authentication solution using Amazon Cognito and Amazon API Gateway, with the client credentials grant. Integrate Amazon Cognito with Amazon API Gateway to create a secure REST API. Test it out using Postman, where you can enter the invoke URL and see the successful read/write messages.
Now is the time to accelerate your business modernization journey. Reach out to your AWS team, and together we’ll show you how to leverage the full potential of your digital assets and creating a scalable, manageable, and secure infrastructure that can adapt to your evolving business needs.