Skip to main content

API Gateway REST API Authorizers Enabled

Overview

This check verifies that your Amazon API Gateway REST APIs have proper authorization controls. It ensures that either an API-level authorizer exists or all resource methods have authorization configured (not set to NONE). This prevents unauthenticated access to your API endpoints.

Risk

Without proper authorization on your API Gateway methods:

  • Data exposure: Attackers can access sensitive data through unprotected endpoints
  • Unauthorized actions: Malicious users can invoke backend operations without authentication
  • Cost overruns: Unprotected APIs can be abused, generating unexpected charges from traffic spikes
  • Service disruption: Abuse of open endpoints can lead to throttling or denial of service

Remediation Steps

Prerequisites

  • AWS account access with permissions to modify API Gateway configurations
  • Knowledge of which authorization method fits your use case (Cognito, Lambda authorizer, or IAM)

AWS Console Method

  1. Sign in to the AWS Management Console
  2. Navigate to API Gateway
  3. Select your REST API from the list
  4. In the left navigation, click Authorizers
  5. Click Create authorizer and choose one of the following:

Option A: Cognito User Pool Authorizer (best for user-facing apps)

  • Name: Enter a descriptive name (e.g., my-cognito-authorizer)
  • Type: Select Cognito
  • Cognito user pool: Select your existing user pool
  • Token source: Enter Authorization
  • Click Create authorizer

Option B: Lambda Authorizer (best for custom authentication logic)

  • Name: Enter a descriptive name (e.g., my-lambda-authorizer)
  • Type: Select Lambda
  • Lambda function: Select your authorizer function
  • Lambda invoke role: Leave blank (API Gateway will use resource-based policy)
  • Token source: Enter Authorization
  • Click Create authorizer
  1. After creating the authorizer, go to Resources in the left navigation
  2. For each method (GET, POST, etc.) that shows Auth: NONE:
    • Click on the method
    • Click Method request
    • Under Authorization, select your newly created authorizer
    • Click the checkmark to save
  3. Click Deploy API and select your deployment stage
AWS CLI (optional)

List your REST APIs:

aws apigateway get-rest-apis --region us-east-1

Check existing authorizers for an API:

aws apigateway get-authorizers \
--rest-api-id <your-api-id> \
--region us-east-1

Create a Cognito User Pool authorizer:

aws apigateway create-authorizer \
--rest-api-id <your-api-id> \
--name my-cognito-authorizer \
--type COGNITO_USER_POOLS \
--provider-arns arn:aws:cognito-idp:us-east-1:<account-id>:userpool/<pool-id> \
--identity-source 'method.request.header.Authorization' \
--region us-east-1

Create a Lambda authorizer:

aws apigateway create-authorizer \
--rest-api-id <your-api-id> \
--name my-lambda-authorizer \
--type TOKEN \
--authorizer-uri 'arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:<account-id>:function:<function-name>/invocations' \
--identity-source 'method.request.header.Authorization' \
--authorizer-result-ttl-in-seconds 300 \
--region us-east-1

Apply the authorizer to a method:

aws apigateway update-method \
--rest-api-id <your-api-id> \
--resource-id <resource-id> \
--http-method GET \
--patch-operations op=replace,path=/authorizationType,value=CUSTOM op=replace,path=/authorizerId,value=<authorizer-id> \
--region us-east-1

Deploy the API to apply changes:

aws apigateway create-deployment \
--rest-api-id <your-api-id> \
--stage-name prod \
--region us-east-1
CloudFormation (optional)
AWSTemplateFormatVersion: '2010-09-09'
Description: API Gateway REST API with Cognito Authorizer

Parameters:
UserPoolArn:
Type: String
Description: ARN of the Cognito User Pool for authorization

Resources:
MyRestApi:
Type: AWS::ApiGateway::RestApi
Properties:
Name: my-secure-api
Description: REST API with authorization enabled

CognitoAuthorizer:
Type: AWS::ApiGateway::Authorizer
Properties:
Name: cognito-authorizer
Type: COGNITO_USER_POOLS
RestApiId: !Ref MyRestApi
IdentitySource: method.request.header.Authorization
ProviderARNs:
- !Ref UserPoolArn

MyResource:
Type: AWS::ApiGateway::Resource
Properties:
RestApiId: !Ref MyRestApi
ParentId: !GetAtt MyRestApi.RootResourceId
PathPart: secure-resource

MyMethod:
Type: AWS::ApiGateway::Method
Properties:
RestApiId: !Ref MyRestApi
ResourceId: !Ref MyResource
HttpMethod: GET
AuthorizationType: COGNITO_USER_POOLS
AuthorizerId: !Ref CognitoAuthorizer
Integration:
Type: MOCK
RequestTemplates:
application/json: '{"statusCode": 200}'
IntegrationResponses:
- StatusCode: 200
MethodResponses:
- StatusCode: 200

ApiDeployment:
Type: AWS::ApiGateway::Deployment
DependsOn: MyMethod
Properties:
RestApiId: !Ref MyRestApi

ApiStage:
Type: AWS::ApiGateway::Stage
Properties:
RestApiId: !Ref MyRestApi
DeploymentId: !Ref ApiDeployment
StageName: prod

Outputs:
ApiEndpoint:
Description: API Gateway endpoint URL
Value: !Sub 'https://${MyRestApi}.execute-api.${AWS::Region}.amazonaws.com/prod'

Deploy the template:

aws cloudformation deploy \
--template-file api-gateway-authorizer.yaml \
--stack-name api-gateway-authorizer-stack \
--parameter-overrides UserPoolArn=arn:aws:cognito-idp:us-east-1:<account-id>:userpool/<pool-id> \
--region us-east-1
Terraform (optional)
resource "aws_api_gateway_rest_api" "secure_api" {
name = "my-secure-api"
description = "REST API with authorization enabled"
}

resource "aws_api_gateway_authorizer" "cognito" {
name = "cognito-authorizer"
rest_api_id = aws_api_gateway_rest_api.secure_api.id
type = "COGNITO_USER_POOLS"
provider_arns = [var.cognito_user_pool_arn]
identity_source = "method.request.header.Authorization"
}

resource "aws_api_gateway_resource" "secure_resource" {
rest_api_id = aws_api_gateway_rest_api.secure_api.id
parent_id = aws_api_gateway_rest_api.secure_api.root_resource_id
path_part = "secure-resource"
}

resource "aws_api_gateway_method" "secure_method" {
rest_api_id = aws_api_gateway_rest_api.secure_api.id
resource_id = aws_api_gateway_resource.secure_resource.id
http_method = "GET"
authorization = "COGNITO_USER_POOLS"
authorizer_id = aws_api_gateway_authorizer.cognito.id
}

resource "aws_api_gateway_deployment" "deployment" {
rest_api_id = aws_api_gateway_rest_api.secure_api.id

depends_on = [aws_api_gateway_method.secure_method]

lifecycle {
create_before_destroy = true
}
}

resource "aws_api_gateway_stage" "prod" {
rest_api_id = aws_api_gateway_rest_api.secure_api.id
deployment_id = aws_api_gateway_deployment.deployment.id
stage_name = "prod"
}

variable "cognito_user_pool_arn" {
description = "ARN of the Cognito User Pool"
type = string
}

output "api_endpoint" {
value = aws_api_gateway_stage.prod.invoke_url
}

For a Lambda authorizer instead:

resource "aws_api_gateway_authorizer" "lambda" {
name = "lambda-authorizer"
rest_api_id = aws_api_gateway_rest_api.secure_api.id
type = "TOKEN"
authorizer_uri = aws_lambda_function.authorizer.invoke_arn
authorizer_credentials = aws_iam_role.invocation_role.arn
identity_source = "method.request.header.Authorization"
authorizer_result_ttl_in_seconds = 300
}

Verification

After configuring authorization, verify it is working:

  1. Go to API Gateway in the AWS Console
  2. Select your REST API
  3. Click Authorizers and confirm your authorizer shows as created
  4. Click Resources and verify each method shows your authorizer (not Auth: NONE)
  5. Test by calling an endpoint without a valid token - it should return a 401 Unauthorized response
CLI verification commands

List all authorizers for your API:

aws apigateway get-authorizers \
--rest-api-id <your-api-id> \
--region us-east-1

Expected output shows your authorizer:

{
"items": [
{
"id": "abc123",
"name": "my-cognito-authorizer",
"type": "COGNITO_USER_POOLS",
"providerARNs": [
"arn:aws:cognito-idp:us-east-1:123456789012:userpool/us-east-1_xxxxx"
],
"identitySource": "method.request.header.Authorization"
}
]
}

Check a specific method's authorization setting:

aws apigateway get-method \
--rest-api-id <your-api-id> \
--resource-id <resource-id> \
--http-method GET \
--region us-east-1

Verify authorizationType is not NONE:

{
"httpMethod": "GET",
"authorizationType": "COGNITO_USER_POOLS",
"authorizerId": "abc123"
}

Additional Resources

Notes

  • Authorizer types: Choose based on your use case:
    • Cognito User Pools: Best for applications with user sign-up/sign-in flows
    • Lambda authorizer: Best for custom authentication logic (e.g., validating third-party tokens)
    • IAM: Best for service-to-service communication using AWS credentials
  • Token caching: Lambda authorizers cache results by default (300 seconds). Adjust authorizerResultTtlInSeconds based on your security needs
  • Deployment required: After changing authorizers, you must deploy the API for changes to take effect
  • Defense in depth: Consider combining authorizers with AWS WAF, throttling, and resource policies for additional protection
  • Testing: Always test your API after adding authorization to ensure legitimate requests still work