Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: API Gateway Authorizer support in SAM Local #137

Closed
azcdev opened this issue Sep 24, 2017 · 156 comments
Closed

Feature Request: API Gateway Authorizer support in SAM Local #137

azcdev opened this issue Sep 24, 2017 · 156 comments

Comments

@azcdev
Copy link

azcdev commented Sep 24, 2017

I'm using the tool to spin up locally an API gateway and run my lambda functions. However, I don't know how to configure an authorizer in template.yml

In my template.yml file, I have the following configuration:

JwtAuthorizerFunction:
    Type: AWS::Serverless::Function
    Properties:
      Environment:
        Variables:
          JWT_SECRET: '<<secret>>'
      Handler: authorizers.jwt
      Runtime: nodejs6.10
      Role:
        Fn::ImportValue:
          !Join ['-', [!Ref 'ProjectId', !Ref 'AWS::Region', 'LambdaTrustRole']]

If I understand the authorizers documentation correctly, I should be able to add the following configurations in order to configure my authorizer

Authorizer: 
  Type: "AWS::ApiGateway::Authorizer"
  Properties: 
    AuthorizerCredentials: 
      Fn::GetAtt: 
        - "LambdaInvocationRole"
        - "Arn"
    AuthorizerResultTtlInSeconds: "300"
    AuthorizerUri: "arn:aws:lambda:us-east-1:<<myarn>>:function:<<lambda function arn>>"
    Type: "TOKEN"
    IdentitySource: "method.request.header.Authorization" 
    Name: "DefaultAuthorizer"
    RestApiId: 
      Ref: "RestApi"

Everything up until that point works fine. If I run
sam validate the output is Valid!
sam local start-api executes without a problem.

However, I don't know how to configure the custom authorizer in my lambda functions. I've read the AWS::Serverless::Function documentation but I couldn't find anything relevant to my issue. Furthermore, there are two issues about adding support for AuthorizationType to the API but it's unclear whether this support will ever be added, or if it has been added already.

Any help pointing in the right direction is greatly appreciated!

@PaulMaddox
Copy link
Contributor

Hi @alanchavez88,

Currently configuring a custom authorizer isn't supported when running locally with SAM Local.

I'll leave this issue open as a feature request for our backlog.

Thanks

@azcdev
Copy link
Author

azcdev commented Sep 25, 2017

Thanks @PaulMaddox for the response!

If I understand the model correctly, it shouldn't matter if my custom authorizer does not run locally, right? In AWS, only authorized requests can trigger the lambda function, correct?

@sanathkr
Copy link
Contributor

Yes, an authorization request should trigger the Lambda in AWS cloud

@ghost
Copy link

ghost commented Sep 29, 2017

I'm wondering how I may use a Cognito Authorizer, is there sample for that? I've gone through all the 5 samples of SAM template.ymls on the internet and am not able to see how I may do so.

Should I just rely on the swagger export? I am migrating an existing hand-build API Gateway to SAM. Thanks for help!

@bradwoods
Copy link

I'm also looking for examples of how to integrate a Cognito Authorizer with lambdas made via SAM templates.

@sanathkr sanathkr added type/feature Feature request and removed feature request labels Jan 7, 2018
@mohithg
Copy link

mohithg commented Jan 10, 2018

This is a good to have feature in SAM Local, so we can test the authorization functions before deploying

@sujithsnair86
Copy link

Hi is there a resolution yet for including Custom Authoriser lambda over SAM template itself or is this still a feature request AWS SAM Team is working on?

@ThomasSmWatson
Copy link

My database url will not work as it contains '=' and other special characters, int he env variables.
How would I get around this? This is a reliant to my company

@gregaeq
Copy link

gregaeq commented Mar 22, 2018

Interested in this feature as well. Attempting to use sam-local to auth with Cognito before making subsequent requests.

@kanchen
Copy link

kanchen commented Mar 30, 2018

Same here. Anyone knows the timeline to support SAM local custom authorizer ?

@margic
Copy link

margic commented Apr 7, 2018

@alanchavez88 did you ever figure out how to configure an authorizer, I notice that the question was never answered. It went off on a tangent about Sam local.

@azcdev
Copy link
Author

azcdev commented Apr 7, 2018

@margic no, I never figured it out. I ended up assuming that it worked and moved on :( If you find a way to do it please post it here.

@kind3r
Copy link

kind3r commented Apr 10, 2018

Hi, I wrote a small tutorial about how I use custom authorizers. While this does not work when running locally, it does work when being deployed. Hope it helps.

Add an API Gateway custom authorizer

Resource summary:

ApiGateway - AWS::Serverless::Api - The API definition
ApiGatewayAuthorizerRole - AWS::IAM::Role - Role for API Gateway to be able to invoke our custom authorizer function
CustomAuthorizerFunction - AWS::Serverless::Function - The Authorizer function
CustomAuthorizerFunctionRole - AWS::IAM::Role - Role of the custom authorizer function to be able to be invoked and access needed resources

ApiGateway invokes CustomAuthorizerFunction which returns a policy that will allow or deny the further invocation of your path function. For more details see Introducing custom authorizers in Amazon API Gateway

Step by step

  • You must define an AWS::Serverless::Api resource that must include the swagger API definition in the DefinitionBody. You cannot use DefinitionUri as CloudFormation will only reference the external file, but not do any of it's variable replacement magic, so you have to include the full swagger API definition inside the aws-sam template.
ApiGateway:
  Type: AWS::Serverless::Api
  Properties:
    StageName: prod
    DefinitionBody:
      swagger: "2.0"
      info:
        title: 
          Ref: AWS::StackName
        description: My API that uses custom authorizer
        version: 1.0.0
      securityDefinitions:
        ...
      paths:
        ...
  • Add a security definition to your API definition for your custom authorizer. This should include the reference to your custom authorizer function CustomAuthorizerFunction and the role assumed by API Gateway when it will invoke the authorizer function ApiGatewayAuthorizerRole. In our example we define that header variable Authorization will hold the authorization token needed for our custom authorizer to work.
securityDefinitions:
  CustomAuthorizer:
    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/${CustomAuthorizerFunction.Arn}/invocations
      authorizerCredentials:
        Fn::Sub: ${ApiGatewayAuthorizerRole.Arn}
      authorizerResultTtlInSeconds: 60
  • Add security requirement for each of the path you want to protect with your custom authorizer. Adding a global security requirement does not seem to work.
paths:
  ...
  "/somepath":
    post:
      security:
        - CustomAuthorizer: []
      ...
  • Create your authorizer function resource just like you would for any regular function.
CustomAuthorizerFunction:
  Type: AWS::Serverless::Function
  Properties:
    Runtime: nodejs6.10
    Handler: index.handler
    ...
    Role:
      Fn::Sub: ${CustomAuthorizerFunctionRole.Arn}
  • Create a role for API Gateway to be able to invoke the authorizer function.
ApiGatewayAuthorizerRole:
  Type: AWS::IAM::Role
  Properties:
    AssumeRolePolicyDocument: 
      Version: "2012-10-17"
      Statement: 
        - 
          Effect: "Allow"
          Principal: 
            Service: 
              - "apigateway.amazonaws.com"
          Action: 
            - sts:AssumeRole
    Policies: 
      - 
        PolicyName: "InvokeAuthorizerFunction"
        PolicyDocument: 
          Version: "2012-10-17"
          Statement: 
            - 
              Effect: "Allow"
              Action:
                - lambda:InvokeAsync
                - lambda:InvokeFunction
              Resource:
                Fn::Sub: ${CustomAuthorizerFunction.Arn}
  • Create a role for your authorizer function to be able to be invoked and access the resources you need.
CustomAuthorizerFunctionRole:
  Type: AWS::IAM::Role
  Properties:
    AssumeRolePolicyDocument: 
      Version: "2012-10-17"
      Statement: 
        - 
          Effect: "Allow"
          Principal: 
            Service: 
              - "lambda.amazonaws.com"
          Action: 
            - sts:AssumeRole
    ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
    Policies:
      ...

@Jun711
Copy link

Jun711 commented May 24, 2018

Is there any example for cognito authorizer?

@sanathkr
Copy link
Contributor

@kind3r This is an excellent tutorial. Something a lot of people will find it very useful. Will you be interested in submitting this as a pull request to the SAM Repo docs please? https://github.com/awslabs/serverless-application-model/tree/develop/docs

@nk2580
Copy link

nk2580 commented Jul 20, 2018

given that the swagger support is for version 2 and not OpenAPI 3 i would expect this feature to come out in the next release. seems like a HUGE oversight in terms of API definition to not allow authorisation in SAM templates.

have spent the last two days trying to get the version 2 swagger def to work in SAM, long story short. i may as well write a full cloudformation stack.

i will definitely be looking into other services soon if this feature isn't implemented.

@setuk
Copy link

setuk commented Jul 25, 2018

Got this working - thanks!

@OndeVai
Copy link

OndeVai commented Nov 27, 2018

I can't find a simple example of using a Cognito authorizer in an Api event event of a lambda function

@abiodunjames
Copy link

abiodunjames commented Jan 9, 2019

None of the examples given here worked for me. I finally followed this https://github.com/awslabs/serverless-application-model/blob/master/examples/2016-10-31/api_lambda_request_auth/template.yaml and i got it working.

My custom authorizer cloud formation definition:

RestApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Prod
      Auth:
        DefaultAuthorizer: ApiAuthorizer
        Authorizers:
          ApiAuthorizer:
            FunctionPayloadType: TOKEN
            FunctionArn: !GetAtt CustomAuthorizerFunction.Arn
            FunctionInvokeRole: !GetAtt CustomAuthorizerFunctionRole.Arn
            Identity:
              Headers:
              - Authorization
              ReauthorizeEvery: 300

@nk2580
Copy link

nk2580 commented Jan 9, 2019

For those playing at home, this relies on the idtoken which cannot be explicitly invalidated. If you never want to log a user out by invalidating the token then it’s a great fit. But if you’re needing to invalidate a token on behalf of a user then you should implement a custom authoriser that checks the access token

@GeekOnGadgets
Copy link

Does anyone know if we can harcode function arn in FunctionArn?

@nk2580
Copy link

nk2580 commented Jan 14, 2019

Not sure why you would want to do that.. are you defining an authoriser in the same Sam template as the inline swagger markup?

FWIW I found the best way to manage a custom authoriser was to make a separate cloudformation or Sam stack with that function on its own and then output the ARN. Then reference it in the Sam templates that have swagger definitions for authorisation

@GeekOnGadgets
Copy link

@nk2580 thanks for replying. Sorry that was pure for testing purpose. I have a separate sam stack for custom authoriser which gets deployed and then a separate stack for functions. But somehow it was not working and was unable to find any example. So decided to give a try with hardcode one.

custom autoriser sam template.yml

AWSTemplateFormatVersion: "2010-09-09"
Transform: "AWS::Serverless-2016-10-31"

Description: >-   
  A custom authoriser to verify JWT token.

Globals:
  Function:
    Runtime: nodejs8.10

Resources:
  Authoriser:
    Type: "AWS::Serverless::Function"
    Properties:
      FunctionName: test-authoriser
      CodeUri: src/
      Handler: index.handler

Outputs:
  AuthoriserArn:
    Description: The Arn of the created autoriser
    Value: !GetAtt Authoriser.Arn

and below is my another stack where I want to reference the custom authoriser

AWSTemplateFormatVersion: "2010-09-09"
Transform: "AWS::Serverless-2016-10-31"

Globals:
  Function:
    Runtime: nodejs8.10
  Api:
    Cors:
      AllowMethods: "'*'"
      AllowHeaders: "'*'"
      AllowOrigin: "'*'"

Resources:
  TestApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: dev
      Auth:
        DefaultAuthorizer: Test-Authorizer
        Authorizers:
          Test-Authorizer:
            FunctionArn: arn:aws:lambda:region:account-number:function:function-name
            Identity:
              Header: Authorizer
              ValidationExpression: ^Bearer [-0-9a-zA-Z\._]*$
              ReauthorizeEvery: 30 # seconds
  Test:
    Type: "AWS::Serverless::Function"
    Properties:
      FunctionName: test-function
      CodeUri: src/test
      Handler: index.test
      Events:
        EndPoint:
          Type: Api
          Properties:
            RestApiId: !Ref TestApi
            Path: /test
            Method: get
            Auth:
              Authorizer: Test-Authorizer

And this where i have very limited knowledge how to achieve this. Any help would be highly appreciated. Thanks

@jfuss jfuss removed priority/2-important stage/pm-review Waiting for review by our Product Manager, please don't work on this yet labels Dec 20, 2022
@jmcaree-gp
Copy link

Out of curiosity, is it possible to run your authorizer function locally using sam local invoke "FunctionName" -e event.json? I'd like to test the function is working ok before deploying up, just to eliminate the possibility that it's not correct.

@abelmcelroy
Copy link

abelmcelroy commented Dec 22, 2022

@jmcaree-gp good call. And yes, that works. What i ended up doing as a work around is jerry-rigging together a lambda that takes the source code of two other lambdas (an authorizer and an endpoint) and runs them in sequence in a single runtime (I'm using typescript). It's highly imperfect but it at least approximates the way my deployed infra's request flow works.

I don't think i would recommend my own solution and eagerly await a day when I can test my APIGW with authorizers and all locally.

@cyrfer
Copy link

cyrfer commented Jan 18, 2023

The only reason I'm using SAM is to run locally. It's unfortunate such a critical piece does not work locally.

@tawheedmanzoor
Copy link

This may be a useful workaround for some of us here:
[https://medium.com/@TawheedM/aws-sam-cli-advanced-testing-running-locally-when-authorizer-is-enabled-9a328d275b7]

Allows you to test locally with hardcoded values for authorizer-injected elements.

@fabianorodrigo
Copy link

More than a half decade has passed since the original post ... :/

@peejayess
Copy link

Please can we get an update on when support for Authorisers will be implemented in sam local start-api?

This ticket has been outstanding for several years and I'm finding very little information on when it will be provided. I'm a little surprised it hasn't been given a higher priority given that it prevents fully testing any application with authorisation, which, surely, must be the majority.

@lucashuy
Copy link
Contributor

Hi, thanks for raising your concerns. While I unfortunately do not have a date for when this will be complete, implementation of custom Lambda authorizer support for sam local start-api is currently underway.

@alb3rtuk
Copy link

alb3rtuk commented Apr 9, 2023

Would love to see this when it's built and ready to use. @lucashuy Please keep us updated :)

@lucashuy
Copy link
Contributor

Hi all, custom Lambda authorizer support for sam local start-api has been released as of SAM CLI v1.80.0. Feel free to create new issues or discussion threads if there are any problems or features that would fit for SAM CLI.

@github-actions
Copy link
Contributor

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see.
If you need more assistance, please either tag a team member or open a new issue that references this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.

@nickls
Copy link

nickls commented Apr 21, 2023

For anyone trying to get this working:

  • You'll need to explicitly add FunctionPayloadType: TOKEN even though that is the default value.
  • Alias function ARN do not work for the FunctionArn as they fail a format sanity check.

@ChronosMasterOfAllTime
Copy link

@lucashuy nice work! Can we please get a usage tutorial on this new feature? I have tried getting this to work and am referencing a local authorizer, yet it is still "not found". Usage details would be great 👍

@supagu
Copy link

supagu commented Jul 25, 2023

Is there a proper example on how to do this?

@ChronosMasterOfAllTime
Copy link

Is there a proper example on how to do this?

There isn't. I requested documentation in issue #5172

@le0kar0ub1
Copy link

Hi, for those which are struggling to make the thing works, I just found how to after some long hours.
The problems seems to be that:

  • you MUST NOT provide a FunctionName field in your lambda authorizer.
  • you MUST provide FunctionPayloadType: TOKEN in the API Auth despite the fact that it's the default value.

Minimal example:

ApiGateway:
    Type: AWS::Serverless::Api
    Properties:
      StageName: dev
      Auth:
        AddDefaultAuthorizerToCorsPreflight: false
        DefaultAuthorizer: Authorizer
        Authorizers:
          Authorizer:
            FunctionPayloadType: TOKEN
            FunctionArn: !GetAtt Authorizer.Arn
            Identity:
              Header: Authorization
              ReauthorizeEvery: 300

Authorizer:
    Type: AWS::Serverless::Function
    Properties:
      Runtime: nodejs18.x
      CodeUri: path/to/Authorizer
      Handler: app.handler
      Timeout: 5

SAM CLI version 1.97.0
AWS CLI version 2.7.21

Hope this can save some hours of many !

@Willis0826
Copy link

a working TypeScript example can be found here as well.

@CeccoCQ
Copy link

CeccoCQ commented Sep 27, 2023

Hi @Willis0826,
I'm currently working on a project that uses AWS Serverless HttpApi (Type: AWS::Serverless::HttpApi). I was wondering if you have any experience with integrating Lambda Authorizer in this V2 version of the API Gateway?

@Willis0826
Copy link

@CeccoCQ Hey, sorry for the late reply. I tried HTTP APIs (V2), and it works great. Please refer to this example

@CeccoCQ
Copy link

CeccoCQ commented Oct 2, 2023

Hi @Willis0826 , thanks for you example!
I have a doubt regarding my case, following your sample.

With this template.yml and these resources:

  ApiGateway:
    Type: AWS::Serverless::HttpApi
    Properties:
      StageName: !Ref AppEnv
      CorsConfiguration: ........
      AccessLogSettings: ...........
      Auth:
        DefaultAuthorizer: CustomLambdaAuthorizer
        Authorizers:
          CustomLambdaAuthorizer:
            AuthorizerPayloadFormatVersion: 2.0
            EnableSimpleResponses: True
            FunctionArn: !GetAtt AuthorizerFunction.Arn
            Identity:
              Headers:
                - Authorization
              ReauthorizeEvery: 5
      Domain:.........

  AuthorizerFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: ./app-identity/authorizer
      Runtime: nodejs16.x
      Handler: service.handler
      FunctionName: "app-authorizer"
      Layers:
        - !Ref CommonsLayer
      Environment: .......
      
  AuthorizerResourcePolicy:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !GetAtt AuthorizerFunction.Arn
      Principal: apigateway.amazonaws.com
      SourceArn: !Sub arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ApiGateway}/*      
      
  ApiUsersFunction:
    Type: AWS::Serverless::Function
    Properties:
      Role: ...
      Runtime: nodejs16.x
      CodeUri: ./app-identity/users-api
      FunctionName: users-api
      Handler: service.handler
      Layers:
        - !Ref CommonsLayer      
      Environment: ......
      Events:
        ReadItems:
          Type: HttpApi
          Properties:
            ApiId: !Ref ApiGateway
            Path: /api/users
            Method: GET

When running sam local start-api -n envs.json --skip-pull-image --warm-containers EAGER, if I use curl -H "Authorization: abc" http://127.0.0.1:3000/api/users or curl http://127.0.0.1:3000/api/users, it seems that the AuthorizerFunction isn't invoked (I have a console.log("Hello authorizer") inside), but the request is processed directly by ApiUsersFunction.

What is wrong?

@Willis0826
Copy link

Willis0826 commented Oct 2, 2023

@CeccoCQ the AuthorizerPayloadFormatVersion field should be "2.0" (a string) instead of 2.0. If you run sam build with AuthorizerPayloadFormatVersion: 2.0, you should see an error message Error: 'AuthorizerPayloadFormatVersion' must be of type string for Lambda Authorizer 'LambdaTokenAuthorizer'..

Am thinking maybe you can create an issue in my example repository. we can figure it out there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests