When building serverless APIs, security is critical. One common way to secure APIs is by requiring clients to present a JWT token.
AWS API Gateway supports Lambda Authorizers, allowing you to write custom authorization logic using a Lambda function.
In today's post, we’ll cover:
- What is a Lambda Authorizer?
- How to build a simple Lambda Authorizer with Node.js
- How to connect it to your API Gateway with AWS SAM
🧠 What Is a Lambda Authorizer?
A Lambda Authorizer is a Lambda function that AWS API Gateway calls before forwarding the request to your main Lambda handler.
It can:
- Validate a JWT token
- Verify user roles/permissions
- Allow or deny access based on custom logic
You can write the logic yourself, giving you maximum flexibility compared to built-in IAM or Cognito authorizers.
🛠 Step 1: Create the Authorizer Lambda
Here’s a simple authorizer.ts example:
import { APIGatewayTokenAuthorizerEvent, APIGatewayAuthorizerResult } from "aws-lambda";
import { Logger } from "@aws-lambda-powertools/logger";
import { SSMClient, GetParameterCommand } from "@aws-sdk/client-ssm";
import jwt from "jsonwebtoken";
const ssmClient = new SSMClient();
const logger = new Logger();
const secretName = process.env.SECRET_NAME!
const generatePolicy = (principalId, effect, resource) => ({
principalId,
policyDocument: {
Version: '2012-10-17',
Statement: [
{
Action: 'execute-api:Invoke',
Effect: effect,
Resource: resource,
},
],
},
});
export const handler = async (event: APIGatewayTokenAuthorizerEvent): Promise<APIGatewayAuthorizerResult> => {
const token = event.authorizationToken
if (!token) {
throw new Error("Unauthorized");
}
const command = new GetParameterCommand({ Name: secretName, WithDecryption: true });
const response = await ssmClient.send(command);
const secret = response.Parameter!.Value!;
try {
const decoded = jwt.verify(token, secret);
return generatePolicy('user', 'Allow', event.methodArn);
} catch (error) {
logger.error("JWT verification failed", err);
throw new Error("Unauthorized");
}
};
📜 Step 2: Define the Authorizer in template.yml
Resources:
AuthorizerFunction:
Type: AWS::Serverless::Function
Properties:
Handler: authorizer.handler
Runtime: nodejs22.x
Environment:
Variables:
JWT_SECRET: "your-secret-here"
Policies:
- Statement:
Effect: Allow
Action:
- ssm:GetParameter
Resource: "[path-to-resource]"
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
Runtime: nodejs22.x
Events:
HelloWorldApi:
Type: Api
Properties:
Path: /hello
Method: get
RestApiId: !Ref MyApi
MyApi:
Type: AWS::Serverless::Api
Properties:
StageName: prod
Auth:
DefaultAuthorizer: LambdaAuthorizer
Authorizers:
LambdaAuthorizer:
FunctionArn: !GetAtt AuthorizerFunction.Arn
⚡️ Bonus Tip: HTTP API + JWT Authorizers
If you're using HTTP API instead of REST API, you can configure a JWT Authorizer without needing a custom Lambda Authorizer — built-in, easier, and faster!
Resources:
MyHttpApi:
Type: AWS::Serverless::HttpApi
Properties:
Auth:
Authorizers:
MyJwtAuthorizer:
JwtConfiguration:
issuer: https://your-issuer.com
audience:
- your-audience
IdentitySource: "$request.header.Authorization"
DefaultAuthorizer: MyJwtAuthorizer
✅ Benefits:
- No Lambda function to maintain
- Faster authentication (native integration)
- Lower cost
Conclusion
Using Lambda Authorizers with JWT gives you powerful, flexible API security.
✅ Now your API is secured with a custom Lambda Authorizer that verifies JWT tokens.
✅ Full control over authentication and authorization.
✅ For simple cases, prefer HTTP API + Native JWT authorizers for speed and simplicity