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