Secure AWS API Gateway Endpoints with a Custom Lambda Authorizer

When building REST APIs on AWS API Gateway, security is paramount. Protecting your endpoints ensures that only authorized users can access your resources. A custom Lambda authorizer lets you implement your authentication and authorization logic for API Gateway. This blog will guide you through creating a custom authorizer using static credentials (for testing) and Auth0 (for production).

What is a Custom Authorizer?

A custom authorizer is a Lambda function that you attach to an API Gateway route. It validates incoming requests based on authentication tokens or headers and then generates a policy document to grant or deny access.

Custom authorizers are perfect when:

  • You need to implement custom authentication logic.
  • You use an external identity provider like Auth0, Cognito, or Okta.
  • Default API Gateway authorizers don’t meet your needs.

Use Case

We’ll create a custom authorizer that:

  • Validates a username and password (temporarily using static values for testing).
  • Later, it integrates with Auth0 for production-grade authentication.
  • Matches user data with hospital information from the request.
  • Generates access policies dynamically for API Gateway.

Step-by-Step Implementation

1. Create and Write the Lambda Authorizer Function

Lambda Authorizer Function

Here’s the complete Lambda function:

import json
import os
import logging
import base64
import requests
import jwt

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):
try:
print('Event:', event)

# Extract Authorization header
auth = None
try:
auth = event['headers']['Authorization']
except KeyError:
raise Exception("Unauthorized: Authorization header missing")

# Extract username and password from the header
username, password = authorization_header(auth)

# Authenticate user (static for testing, Auth0 for production)
authenticated_data = authenticate_user(username, password)

if authenticated_data:
# Return a successful authorization response
return generate_authorizer_response(True, username)
else:
# Authentication failed
return generate_authorizer_response(False, username, "Invalid credentials")

except Exception as e:
logger.error(f"Error: {str(e)}")
return generate_authorizer_response(False, "Internal Server Error")


def authenticate_user(email, password):
"""
Temporarily authenticate using static credentials.
Replace with Auth0 logic for production.
"""
STATIC_EMAIL = "test@example.com"
STATIC_PASSWORD = "TestPassword123"

if email == STATIC_EMAIL and password == STATIC_PASSWORD:
return {
"nickname": STATIC_EMAIL.split('@')[0],
"email": STATIC_EMAIL
}
else:
print("Authentication failed: Invalid email or password")
return None


def authorization_header(auth_token):
"""
Extract and decode username/password from the Basic Authorization header.
"""
auth = auth_token.split(" ")

if not auth or auth[0].lower() != 'basic':
raise Exception("Unauthorized: Invalid header format")

try:
auth_decoded = base64.b64decode(auth[1]).decode('utf-8')
username, password = auth_decoded.split(':')
except Exception as e:
raise Exception("Unauthorized: Invalid credentials encoding")

return username, password


def generate_authorizer_response(is_authorized, username, additional_info=None):
"""
Generate IAM policy for the API Gateway.
"""
return {
'principalId': username,
'policyDocument': {
'Version': '2012-10-17',
'Statement': [
{
'Action': 'execute-api:Invoke',
'Effect': 'Allow' if is_authorized else 'Deny',
'Resource': '*' # Replace '*' with specific ARNs
}
]
},
'context': {
'additionalInfo': additional_info
}
}

Deploy the Lambda Function

Create the Lambda Function:

  • Open the AWS Lambda Console.
  • Create a new function using Python 3.x.
  • Paste the above code into the function editor.

Permissions:

Attach the AWSLambdaBasicExecutionRole policy to the Lambda execution role.

Secure Your API Endpoints Effortlessly—Start Implementing Custom Lambda Authorizers

Create an API Gateway

To connect the Lambda authorizer with your API:

  • Navigate to the API Gateway Console:
    • Open AWS Management Console > API Gateway.
  • Create a New REST API:
    • Select Create API > REST API > Build.
    • Choose New API.
      • API Name: Enter a descriptive name (e.g., CustomAuthAPI).
      • Description: (Optional) Add details about the API.
      • Endpoint Type: Choose Regional (or Edge-Optimized for global access).
    • Click Create API.

Create API

Add Resources and Methods

Add a Resource:

  • In the API Gateway dashboard, click Actions > Create Resource.
  • Resource Name: Enter the name (e.g., secure-data).
  • Resource Path: /secure-data.
  • Click Create Resource.

Create Resource

Add a Method:

  • Select the newly created resource (/secure-data).
  • Click Actions > Create Method > Select GET.
  • Choose Lambda Function Integration.
  • Specify the name of your Lambda Function and click Save.

Function Integration

Attach the Lambda Function to API Gateway

Go to the API Gateway Console:

  • Choose the API you want to secure.
  • Under Authorizers, create a new authorizer:
    • Type: Lambda
    • Lambda Function: Select the Lambda function you just created.
    • Token Source: Choose Authorization header.

Update the API Gateway Methods:

  • For each method, set the authorizer to the one you just created.
  • Deploy the API.

Best Practices

Restrict Policy Resources:

  • Replace ‘*’ in the policy document with specific ARNs.

Secure Secrets:

  • Use AWS Secrets Manager for storing sensitive environment variables.

Logging:

  • Avoid logging sensitive data such as tokens or passwords.
coma

Conclusion

With a custom Lambda authorizer, you can implement flexible and secure authentication for your AWS API Gateway endpoints. Starting with static credentials and transitioning to Auth0, you can rapidly prototype and scale your solution without compromising security.

Next Steps: Integrate additional identity providers like Cognito, or explore multi-tenancy support in your APIs!

Keep Reading

Keep Reading

  • Service
  • Career
  • Let's create something together!

  • We’re looking for the best. Are you in?