API Gateway Authorization Strategies
Implement robust API authorization using Cognito, Lambda authorizers, and IAM policies for secure API access control.
Securing APIs requires robust authorization mechanisms. AWS API Gateway supports multiple authorization strategies to protect your endpoints while maintaining flexibility.
Cognito User Pool Authorizer
Setup Configuration
CognitoAuthorizer:
Type: AWS::ApiGateway::Authorizer
Properties:
Name: CognitoAuthorizer
RestApiId: !Ref ApiGateway
Type: COGNITO_USER_POOLS
IdentitySource: method.request.header.Authorization
ProviderARNs:
- !GetAtt CognitoUserPool.Arn
ProtectedMethod:
Type: AWS::ApiGateway::Method
Properties:
RestApiId: !Ref ApiGateway
ResourceId: !Ref ProtectedResource
HttpMethod: GET
AuthorizationType: COGNITO_USER_POOLS
AuthorizerId: !Ref CognitoAuthorizer
AuthorizationScopes:
- api/read
- api/write
Token Validation
import jwt
import requests
from functools import lru_cache
@lru_cache(maxsize=1)
def get_cognito_keys(region, user_pool_id):
keys_url = f'https://cognito-idp.{region}.amazonaws.com/{user_pool_id}/.well-known/jwks.json'
response = requests.get(keys_url)
return response.json()['keys']
def validate_token(token, region, user_pool_id, client_id):
keys = get_cognito_keys(region, user_pool_id)
headers = jwt.get_unverified_header(token)
key = next((k for k in keys if k['kid'] == headers['kid']), None)
if not key:
raise ValueError('Invalid token key')
public_key = jwt.algorithms.RSAAlgorithm.from_jwk(key)
return jwt.decode(
token,
public_key,
algorithms=['RS256'],
audience=client_id,
issuer=f'https://cognito-idp.{region}.amazonaws.com/{user_pool_id}'
)
Lambda Authorizer
Token-Based Authorizer
import json
import jwt
import os
def lambda_handler(event, context):
token = event.get('authorizationToken', '').replace('Bearer ', '')
try:
claims = validate_jwt(token)
return generate_policy(
claims['sub'],
'Allow',
event['methodArn'],
context={
'userId': claims['sub'],
'email': claims.get('email'),
'roles': claims.get('custom:roles', '')
}
)
except Exception as e:
print(f"Authorization failed: {e}")
return generate_policy('user', 'Deny', event['methodArn'])
def generate_policy(principal_id, effect, resource, context=None):
policy = {
'principalId': principal_id,
'policyDocument': {
'Version': '2012-10-17',
'Statement': [{
'Action': 'execute-api:Invoke',
'Effect': effect,
'Resource': resource
}]
}
}
if context:
policy['context'] = context
return policy
Request-Based Authorizer
def request_authorizer(event, context):
headers = event.get('headers', {})
query_params = event.get('queryStringParameters', {})
api_key = headers.get('x-api-key')
client_id = query_params.get('client_id')
if not api_key or not validate_api_key(api_key, client_id):
return generate_policy('unknown', 'Deny', event['methodArn'])
client_config = get_client_config(client_id)
return generate_policy(
client_id,
'Allow',
build_resource_arn(event, client_config['allowed_resources']),
context={
'clientId': client_id,
'tier': client_config['tier'],
'rateLimit': str(client_config['rate_limit'])
}
)
IAM Authorization
Resource Policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:role/BackendServiceRole"
},
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:us-east-1:123456789012:api-id/prod/GET/*"
},
{
"Effect": "Deny",
"Principal": "*",
"Action": "execute-api:Invoke",
"Resource": "arn:aws:execute-api:us-east-1:123456789012:api-id/prod/*",
"Condition": {
"NotIpAddress": {
"aws:SourceIp": ["10.0.0.0/8", "192.168.0.0/16"]
}
}
}
]
}
SigV4 Signing
import boto3
from botocore.auth import SigV4Auth
from botocore.awsrequest import AWSRequest
import requests
def call_iam_protected_api(url, method='GET', data=None):
session = boto3.Session()
credentials = session.get_credentials()
request = AWSRequest(method=method, url=url, data=data)
SigV4Auth(credentials, 'execute-api', 'us-east-1').add_auth(request)
response = requests.request(
method=method,
url=url,
headers=dict(request.headers),
data=data
)
return response.json()
Authorization Caching
LambdaAuthorizer:
Type: AWS::ApiGateway::Authorizer
Properties:
Name: CachedLambdaAuthorizer
RestApiId: !Ref ApiGateway
Type: TOKEN
AuthorizerUri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${AuthorizerFunction.Arn}/invocations
AuthorizerResultTtlInSeconds: 300
IdentitySource: method.request.header.Authorization
IdentityValidationExpression: ^Bearer [-a-zA-Z0-9._~+/]+=*$
Working with Warqline
We are a cloud engineering consultancy and an official AWS and Google Cloud partner. If you are running this in production and want a second pair of eyes, we scope work in a free 45-minute technical call: you describe what you are running and what worries you, and we tell you what we would look at first.
Conclusion
Effective API authorization requires selecting the right strategy for your use case. Combine Cognito for user authentication, Lambda authorizers for custom logic, and IAM for service-to-service communication.