Search code examples
amazon-web-servicesaws-api-gateway

How to add API Gateway custom authorizers in an AWS SAM template?


I'm working on some serverless applications and am looking to do all of the deployments using AWS SAM. I'm not finding a lot of information on how to include custom authorizers for my endpoints. There are some (year old) posts that talk about defining them in Swagger (which I'm not using) or Cloudformation.

Does anyone have an example of either of these methods, or know how to define the custom authorizer in the SAM template?


Solution

  • UPDATE: The AWS Serverless Application Model (SAM) now supports defining an API Auth Object as a part of the AWS::Serverless::Api resource:

    https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api-auth-object

    Auth:
      MyLambdaTokenAuth:
        FunctionPayloadType: TOKEN
        FunctionArn: !GetAtt MyAuthFunction.Arn
        Identity:
          Header: Authorization
          ReauthorizeEvery: 300
    

    Original Answer:

    I did eventually get this working using AWS swagger extensions in my template. I have a basic example on my GitHub:

    AWSTemplateFormatVersion: '2010-09-09'
    Transform: AWS::Serverless-2016-10-31
    Description: An example serverless "Hello World" application with a custom authorizer.
    
    Resources:
      ApiGateway:
        Type: AWS::Serverless::Api
        Properties:
          StageName: Prod
          DefinitionBody:
            swagger: 2.0
            info:
              title:
                Ref: AWS::StackName
            securityDefinitions:
              test-authorizer:
                type: apiKey
                name: Authorization
                in: header
                x-amazon-apigateway-authtype: custom
                x-amazon-apigateway-authorizer:
                  type: token
                  authorizerUri:
                    Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${TestAuthorizerFunc.Arn}/invocations
                  authorizerResultTtlInSeconds: 5
            paths:
              "/":
                get:
                  x-amazon-apigateway-integration:
                    httpMethod: post
                    type: aws_proxy
                    uri:
                      Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HelloWorld.Arn}/invocations
                  responses: {}
                  security:
                    - test-authorizer: []
    
      HelloWorld:
        Type: AWS::Serverless::Function
        Properties:
          Handler: lambda_function.lambda_handler
          Runtime: python3.6
          CodeUri: ./HelloWorld
          Events:
            GetApi:
              Type: Api
              Properties:
                Path: /
                Method: get
                RestApiId:
                    Ref: ApiGateway
    
      TestAuthorizerFunc:
        Type: AWS::Serverless::Function
        Properties:
          Handler: lambda_function.lambda_handler
          Runtime: python3.6
          CodeUri: ./TestAuthorizerFunc
    
      TestAuthorizerFuncPerm:
        Type: AWS::Lambda::Permission
        DependsOn:
          - ApiGateway
          - TestAuthorizerFunc
        Properties:
          Action: lambda:InvokeFunction
          FunctionName:
            Ref: TestAuthorizerFunc
          Principal: apigateway.amazonaws.com
    

    In the API Gateway resource, the YAML of the swagger definition is added under the DefinitionBody key. The custom authorizer is defined as:

    securityDefinitions:
      test-authorizer:
        type: apiKey
        name: Authorization
        in: header
        x-amazon-apigateway-authtype: custom
        x-amazon-apigateway-authorizer:
          type: token
          authorizerUri:
            Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${TestAuthorizerFunc.Arn}/invocations
          authorizerResultTtlInSeconds: 5  
    

    Then the authorizer is attached in the definition for the path that it will secure:

    paths:
      "/":
        get:
          x-amazon-apigateway-integration:
            httpMethod: post
            type: aws_proxy
            uri:
              Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HelloWorld.Arn}/invocations
          responses: {}
          security:
            - test-authorizer: []
    

    Code for the Lambda functions can be found here:

    https://github.com/brysontyrrell/Serverless-Hello-World/tree/master/hello-world