In this blog post, we will look at how to configure OAuth authentication for a REST API using AWS Cognito user Pool. We will create a REST API using AWS Lambda and API Gateway, integrate it with Cognito User Pool and create custom OAuth scopes to authenticate and authorize the REST API endpoints.
Overview
At a high level, below are the steps to be performed to setup the REST API and OAuth authentication using Cognito
Create a AWS Lambda function
Create a REST API in AWS API Gateway
Create a Cognito User Pool
Create a Resource Server and define custom scopes
Update the App Client with the custom scopes
Create an Authorizer in API Gateway
Configure the Authorizer and the custom OAuth scope for the API endpoint
Create a user in the Cognito User Pool
Test the API endpoint
1. Create a AWS Lambda function
Let’s create a simple lambda function in Python that just returns a “Hello World” message. This lambda will be configured as the backend for the REST API that we will create next.
Create a new lambda function by following the below steps
Navigate to Lambda service in AWS console and click “Create function” button
Enter “hello-world-lambda” as the “Function Name”
Select the Runtime as “Python 3.9”
Leave rest of the settings to their default value and click “Create function” button
Leave the default lambda function code that is present once the function is created or type in the below code and click the “Deploy” button.
import json
def lambda_handler(event, context):
return {
'statusCode': 200,
'body': json.dumps('Hello World!')
}
2. Create a REST API in AWS API Gateway
Create a new REST API with a single GET endpoint in AWS API Gateway. We will add authentication and authorization to this endpoint in a later step once we have the Cognito setup completed.
Create a REST API by following the below steps
Navigate to API Gateway service in AWS console and click the “Create API” button
Click the “Build” button in the REST API section
In the next screen, in the “Settings” section, enter “hello-world-api” in the “API name” field and select “Edge optimized” for the “Endpoint Type”
Create a Method by selecting “Create Method” from the “Actions” dropdown and then select “GET” as the method type and click the little check mark beside the dropdown
In the GET Setup page, select the checkbox “Use Lambda Proxy Integration” and then enter “hello-world-lambda” in the “Lambda Function” textbox to choose the Lambda that we created in the previous step.
Click “OK” in “Add Permission to Lambda Function” dialog box to provide API Gateway permissions to invoke the lambda functio
3. Create a Cognito User Pool
Create a new Cognito User Pool that will contain the users that can access the REST API using custom OAuth scopes. In this exercise, we will utilize most of the default settings while creating and configuring the Cognito user pool.
Create and configure the Cognito User Pool by following the below steps
Navigate to AWS Cognito service -> “User pools” in AWS console and click the “Create user pool” button to create a new user pool
In the “Configure sign-in experience” step, choose “User name” in the “Cognito user pool sign-in options” section and click the “Next” button
In the “Configure security requirements” step, select “No MFA” in the “Multi-factor authentication” section and click the “Next” button
In the “Configure sign-up experience” step, leave the defaults unchanged and click the “Next” button
In the “Configure message delivery” step, select “Select email with Cognito” option in the “Email” section and click the “Next” button
In the “Integrate your app” step,
Enter “hello-world-user-pool” in the “User pool name” field
Select “Use the Cognito Hosted UI” checkbox
Select “Use a Cognito domain” option and enter “https://hello-world-api” in the “Cognito domain” field
In the “Initial app client” section, enter “hello-world-client” in the “App client name” field, select “Generate a client secret” option, and enter the postman callback URL “https://oauth.pstmn.io/v1/callback” in the “Allowed callback URLs” section
Click the “Next” button
In the “Review and create” step, click the “Create user pool” button
4. Create a Resource Server
A resource server is an OAuth server that authorizes access to protected resources (APIs) by verifying the access token and the access levels based on scopes present in the token. A scope is a level of access that an app can request to a resource.
In the context of this exercise, we will create a resource server and a custom scope that will be later used to protect the endpoint that we created earlier.
Create a resource server and a custom scope by following the below steps
Navigate to Cognito service -> “User pools” -> “hello-world-user-pool” (the one we just created in the previous step) -> “App Integration” tab
In the “Resource servers” section, click the “Create resource server” button
In the “Resource server” section,
Enter “hello-world-resource-server” in the “Resource server name” field
Enter “hello-world-api” in the “Resource server identifier” field
In the “Custom scopes” section, click the “Add custom scope” button
Enter “read.helloworld.message” in the “Scope name” field
Enter “read helloworld message” in the “Description” field
Click the “Create resource server” button
5. Update the custom scope in the app client
We need to update the custom scope we created in the previous step to the app client, so that the client app (the one that uses the client id of this app client), will receive the custom scope in the access token that gets generated.
Update the custom scope in the app client by following the below steps
Navigate to “App Integration” tab and scroll down to the “App clients and analytics” section
Click the “hello-world-client” app to open up the configuration screen for this app client
Click the “Edit” button In the “Hosted UI” section
Scroll down to the bottom of the screen and select the custom scope that we created in the previous step from the “Custom scopes” dropdown
Click the “Save changes” button
6. Create an Authorizer in API Gateway
Now that we have set up the Cognito side of things by creating an OAuth server and defining a custom scope and configuring the scope in the app client, let’s create an Authorizer for the REST API endpoint.
The authorizer will be configured to use the Cognito user pool, to allow the users of this Cognito user pool to access the endpoint. In addition to it, we will also update the OAuth scope, so that in runtime, the scope will be validated against the access token claims, before allowing access to this protected API endpoint.
Create an Authorizer for the REST API endpoint by following the below steps
Navigate to API Gateway service and open the “hello-world-api” that we created earlier
Click the “Authorizers” option from the left navigation menu
Click the “Create New Authorizer” button
Enter “hello-world-authorizer” in the “Name” field
Select the type as “Cognito”
Select the “hello-world-user-pool” Cognito user pool in the “Cognito User Pool” field
Enter “Authorization” in the “Token Source” field
Click the “Create” button
7. Configure the Authorizer and the custom OAuth scope for the API endpoint
As the last step, we need to configure the Authorizer we just created and the custom OAuth scope that we created earlier for the REST API endpoint.
Configure the Authorizer and the custom OAuth scope for the API endpoint by following the below steps
Navigate to API Gateway and open the “hello-world-api” again
In the Resources section, click the “GET” Http Method
Click the “Method Request” box on the right side of the screen
Click the pencil icon in the “Authorization” field and select the “hello-world-authorizer” that we just created and click the check mark to save the selection
Click the pencil icon in the “OAuth Scopes” field and paste the OAuth scope “hello-world-api/read.helloworld.message” that we created earlier. Please note we need to combine both the “Resource server identifier” and the “Custom scope” and then enter that value in the OAuth scope field.
Click the check mark in the OAuth scopes field to persist the scope entered
Select “Deploy API” from the “Actions” dropdown
In the “Deploy API” dialog box, select “[New Stage]” in the “Deployment stage” dropdown and enter “dev” as the “Stage Name”. Click the “Deploy” button
8. Create a user in the Cognito User Pool
We have completed all the configurations that we need to create a REST API endpoint and secure it using Cognito User Pool utilizing OAuth Server and scopes. Before we go ahead and start testing the API using Postman, we need to create a user in the Cognito User Pool using which we will invoke the endpoint.
Create a new user in the Cognito User Pool by following the below steps
Navigate to “hello-world-user-pool” in Cognito and click the “Create user” button in the “Users” section present in the “Users” tab
Select “Send an email invitation” option
Enter a user name in the “User name” field
Enter a valid email address in the “Email address” field.
Enter a password in the “Password” field
Click the “Create user” button
9. Test the API endpoint
Let’s use Postman to test the API endpoint. Postman will act as the client app for this REST API endpoint.
Create a new request in Postman to invoke the hello-world-api by following the below steps
Create a new request by clicking the “Plus” icon and creating a new tab
Select the HTTP Method as “GET” and enter the API endpoint URL. If you don’t have the endpoint URL, then navigate to API Gateway and open the “hello-world-api” and click the “Stages” option in the left navigation menu and click the stage name “dev”. Pick the URL from the top of the screen displayed in the right hand side.
Click the “Authorization” tab
Select “OAuth 2.0” in the “Type” dropdown
In the “Configure New Token” section -> “Configuration Options” tab,
Enter “accessToken” in the “Token Name” field
Select “Authorization Code” in the “Grant Type” dropdown
Select “Authorize using browser” checkbox
Enter the “Auth URL” by appending “/oauth2/authorize” to the “Cognito Domain” value in the Cognito user pool (Cognito Domain will be present in the “App Integration” tab in Cognito user pool. For example: https://hello-world-api.auth.us-east-2.amazoncognito.com/oauth2/authorize
Enter the “Access Token URL” by appending “/oauth2/token” to the “Cognito Domain”. For example: https://hello-world-api.auth.us-east-2.amazoncognito.com/oauth2/token
Enter the “Client ID” and “Client Secret” obtained from the “App client” that we created in the Cognito user pool.
Enter the custom OAuth scope “hello-world-api/read.helloworld.message” in the “Scope” field
Select “Send as Basic Auth Header” in the “Client Authentication” dropdown
Click the “Get New Access Token” button and enter the username / password in the Cognito login screen that opens up in the browser.
Once authenticated it will route back to Postman, accept the access token and use it
Click the “Send” button to invoke the API endpoint which should return a 200 response with the text “Hello World!” in the Response body.
That’s it to configure OAuth Resource Server in the Cognito user pool to protect the REST API endpoints created in API Gateway using custom OAuth scopes.
10. References
Integrate API Gateway with Cognito - https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-integrate-with-cognito.html
Using tokens in Cognito - https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html
Resources Servers in Cognito User Pools - https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-define-resource-servers.html
