How to Secure AWS API Gateway with Amazon Cognito User Pools

In this tutorial, we will walk you through the process of securing your AWS API Gateway using Amazon Cognito user pools. By default, AWS API Gateway lacks authorization and security, making it accessible to anyone who knows the endpoint URL. We will show you how to lock down your API and enforce user authentication, allowing only authorized users to access it.

Prerequisites

Before you begin, you should have the following in place:

1. An AWS account.

2. AWS CLI configured on your local machine.

3. Basic understanding of AWS services like Amazon Cognito, Lambda, and API Gateway.

Now, let’s start by creating an Amazon Cognito user pool, Lambda function, and an API Gateway endpoint. We’ll also set up user authentication and authorization.

Step 1: Create an Amazon Cognito User Pool

Amazon Cognito is a feature-rich service that allows you to create user pools with login functionality. Users in these pools can log in using email, phone numbers, or other identifiers. To begin, follow these steps:

1. Open your AWS Management Console, navigate to Cognito, and create a new user pool. You can use the AWS CLI to create a user pool with the following command:

aws cognito-idp create-user-pool --pool-name YourUserPoolName

2. Configure user pool settings and options according to your requirements. For this tutorial, we’ll use the default settings.

3. Create an App Client within your user pool. You can create an App Client using the AWS CLI:

aws cognito-idp create-user-pool-client --user-pool-id YourUserPoolID --client-name YourAppClientName

4. Define the callback URLs, including login, registration, and logout URLs.

Now you have your Amazon Cognito user pool set up. Users can register, log in, and get authentication tokens.

Step 2: Create a Lambda Function

You’ll need a Lambda function to serve as the resource for your API Gateway. For simplicity, we’ll create a basic Lambda function that returns “Hello, World.” You can replace this with your desired logic. Here’s how to create the Lambda function:

1. Open the AWS Management Console, navigate to Lambda, and create a new Lambda function. You can use the AWS CLI to create a Lambda function:

aws lambda create-function --function-name YourLambdaFunctionName --runtime nodejs --handler index.handler --role YourRoleARN

2. Use a simple Lambda function code that returns a message. For example:

exports.handler = async (event) => {
  const response = {
    statusCode: 200,
    body: JSON.stringify('Hello from Lambda!'),
  };
  return response;
};

Now you have a basic Lambda function that will serve as the resource for your API Gateway. You can customize it further to suit your needs.

Step 3: Create an API Gateway Endpoint

Create an API Gateway to expose your Lambda function as a web service. Follow these steps:

1. Open the AWS Management Console, navigate to API Gateway, and create a new REST API. You can create a REST API using the AWS CLI:

aws apigateway create-rest-api --name YourAPIName

2. Create a resource, e.g., /transactions, and define a GET method (or any other HTTP method based on your requirements). You can create a resource using the AWS CLI:

aws apigateway create-resource --rest-api-id YourAPIID --parent-id YourParentResourceID --path-part transactions

3. Create an integration for the method, connecting it to the Lambda function. You can configure a method and integration using the AWS CLI:

aws apigateway put-method --rest-api-id YourAPIID --resource-id YourResourceID --http-method GET --authorization-type NONE
aws apigateway put-integration --rest-api-id YourAPIID --resource-id YourResourceID --http-method GET --type AWS_PROXY --integration-http-method POST --uri YourLambdaFunctionARN

4. Deploy your API to a stage (e.g., ‘test’). You can deploy your API using the AWS CLI:

aws apigateway create-deployment --rest-api-id YourAPIID --stage-name YourDeploymentStage

5. Note the invoke URL that is generated for your API Gateway. This URL will be used to access your API.

Now you have a functional API Gateway endpoint connected to your Lambda function.

Step 4: Configure Amazon Cognito Authorization

To enforce authentication and authorization, you need to configure your API Gateway with Amazon Cognito. Here’s how:

1. Open the AWS Management Console, navigate to API Gateway, and go to Authorizers. You can create an authorizer using the AWS CLI:

aws apigateway create-authorizer --name YourAuthorizerName --type COGNITO_USER_POOLS --provider-arns YourCognitoUserPoolArn

2. Choose your Amazon Cognito user pool and configure OAuth scopes (e.g., email) for your authorizer.

3. Specify the authorization in your API Gateway method request settings. Refresh the page if the authorizer doesn’t appear initially.

4. Update your deployment stage to apply the new authorizer. You can update the deployment stage using the AWS CLI:

aws apigateway create-deployment --rest-api-id YourAPIID --stage-name YourDeploymentStage

Step 5: Test Your Secure API Gateway

To test your newly secured API Gateway, use a tool like Postman to send requests with an authentication token in the header. You can obtain the token by logging in through your Cognito user pool or by using an identity provider (such as Facebook or Google) integrated with Cognito.

1. Make a POST request to your Cognito user pool’s token endpoint to authenticate and get an access token. Include your Cognito App Client ID and Secret.

2. Use the access token in your API requests by including it in the Authorization header as a Bearer token.

Your API Gateway is now secured with Amazon Cognito user pools, and only authorized users can access it.

Remember to customize your authentication and authorization logic based on your specific requirements and ensure proper resource policies and IAM roles to protect your AWS resources. Additionally, implement error handling and security best practices for your Lambda function and API Gateway.

Implementation using Boto3

to implement the steps mentioned in your initial video using the AWS SDK for Python (Boto3), you will need to create a Cognito User Pool, configure an API Gateway, create a Lambda function, and set up the necessary authorizations. Below are the steps to achieve this:

1. Create a Cognito User Pool:

import boto3

# Create a Cognito client
cognito_client = boto3.client('cognito-idp', region_name='your_region')

# Create a user pool
user_pool = cognito_client.create_user_pool(
    PoolName='YourUserPoolName',
    Policies={
        'PasswordPolicy': {
            'MinimumLength': 8,
            'RequireUppercase': True,
            'RequireLowercase': True,
            'RequireNumbers': True,
            'RequireSymbols': True,
            'TemporaryPasswordValidityDays': 7
        }
    },
    UsernameAttributes=['email'],  # Specify the username attribute
    AutoVerifiedAttributes=['email'],  # Automatically verify the email attribute
    Schema=[
        {
            'Name': 'email',
            'AttributeDataType': 'String',
            'Mutable': False,
            'Required': True
        }
    ]
)

# Get the user pool ID
user_pool_id = user_pool['UserPool']['Id']

# Create an app client for your user pool
app_client = cognito_client.create_user_pool_client(
    UserPoolId=user_pool_id,
    ClientName='YourAppClientName',
    GenerateSecret=False,
    ExplicitAuthFlows=[
        'ALLOW_USER_SRP_AUTH',
        'ALLOW_REFRESH_TOKEN_AUTH',
        'ALLOW_CUSTOM_AUTH',
    ],
)

# Get the app client ID
app_client_id = app_client['UserPoolClient']['ClientId']

2. Set Up API Gateway:

import boto3

# Create an API Gateway client
api_gateway_client = boto3.client('apigateway', region_name='your_region')

# Create a REST API
rest_api = api_gateway_client.create_rest_api(
    name='YourAPIName',
    description='Your API Description'
)

# Get the REST API ID
api_id = rest_api['id']

# Create a resource for your API
resource = api_gateway_client.create_resource(
    restApiId=api_id,
    parentId=api_id,
    pathPart='transactions'  # Resource path
)

# Get the resource ID
resource_id = resource['id']

# Create a GET method for the resource
method = api_gateway_client.put_method(
    restApiId=api_id,
    resourceId=resource_id,
    httpMethod='GET',
    authorizationType='NONE'  # This will be updated later
)

# Set up the integration between the method and your Lambda function (use your Lambda function's ARN)
api_gateway_client.put_integration(
    restApiId=api_id,
    resourceId=resource_id,
    httpMethod='GET',
    type='AWS_PROXY',
    integrationHttpMethod='POST',
    uri='arn:aws:lambda:your_region:your_account_id:function/YourLambdaFunctionName',
)

# Create a deployment for your API
api_gateway_client.create_deployment(
    restApiId=api_id,
    stageName='test'  # Your deployment stage name
)

3. Set Up Lambda Function:

Create your Lambda function using the AWS Lambda console or using the boto3 library.

4. Configure Authorization for API Gateway:

# Update the method to use Cognito User Pool authorization
api_gateway_client.update_method(
    restApiId=api_id,
    resourceId=resource_id,
    httpMethod='GET',
    patchOperations=[
        {
            'op': 'replace',
            'path': '/authorizationType',
            'value': 'COGNITO_USER_POOLS'
        },
        {
            'op': 'replace',
            'path': '/authorizerId',
            'value': 'YourAuthorizerID'
        }
    ]
)

Replace 'YourAuthorizerID' with the actual authorizer ID that you obtained when creating the Cognito User Pool authorizer.

Now, your API Gateway is configured to use Cognito User Pool for authorization, and only authenticated users can access the API. You can use the boto3 library to manage users, sign them up, and generate authentication tokens through your Cognito User Pool.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top