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

Defining CORS when ApiKeyRequired is true results in an OPTIONS method that requires an API key #1786

Closed
egalev opened this issue Nov 9, 2020 · 10 comments

Comments

@egalev
Copy link

egalev commented Nov 9, 2020

Description:

When setting up an API Gateway with {proxy+} integration through SAM, having a required API key prevents the CORS definition from properly responding to OPTIONS requests, since they require an API key as well.

Steps to reproduce the issue:

  1. Define an Api that requires an API key:
Resources:
  BasicAWSApiGateway:
    Type: AWS::Serverless::Api
    Properties:
      StageName: !Ref Environment
      Auth:
        ApiKeyRequired: true
      Cors: "'*'"
      DefinitionBody:
        swagger: "2.0.0"
        info:
          version: 1.0.0
        paths:
          /{proxy+}:
            x-amazon-apigateway-any-method:
              produces:
                - application/json
              parameters:
                - in: path
                  name: proxy
                  required: true
                  type: string
              x-amazon-apigateway-integration:
                uri: !Sub "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${LambdaName}-${Environment}/invocations"
                httpMethod: POST
                type: aws_proxy
                passthroughBehavior: when_no_match
                credentials: !GetAtt ApiGatewayExecutionRole.Arn

Observed result:
The OPTIONS method in API Gateway requires an API Key, blocking CORS since browsers don't add a x-api-key header.

Expected result:
The OPTIONS method should not require an API Key.

@wchengru wchengru added area/resource/api area/swagger stage/bug-repro The issue/bug needs to be reproduced labels Nov 23, 2020
@aahung
Copy link
Contributor

aahung commented May 13, 2021

In https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-api-apiauth.html#sam-api-apiauth-adddefaultauthorizertocorspreflight

We have a AddDefaultAuthorizerToCorsPreflight to control whether DefaultAuthorizer is applied to OPTIONS endpoint or not, but we don't have one for ApiKeyRequired.

According to Fetch Standard

For a CORS-preflight request, request’s credentials mode is always "same-origin", i.e., it excludes credentials

OPTIONS endpoint should work without the need for credential. Propose: not apply Auth to OPTIONS and consider deprecating AddDefaultAuthorizerToCorsPreflight.

@aahung aahung added type/bug-triaged and removed stage/bug-repro The issue/bug needs to be reproduced labels May 13, 2021
@pisaacs
Copy link

pisaacs commented Jun 14, 2021

While this issue is being resolved, are there suggested work-arounds?

@eh-admin
Copy link

eh-admin commented Sep 23, 2021

While this issue is being resolved, are there suggested work-arounds?

potential workarounds:

  1. Disable API Key auth (if you can live without it)
  2. Same as #1, but re-add the API Key auth handling INSIDE your lambda function (if the API Gateway endpoint points to a lambda function) - i.e. manually verify the contents of the x-api-key header inside your lambda function(s)
  3. Same as #1, but instead replace it with a custom lambda authorizer that does the same as #2 (for the cases that your API Gateway endpoint is not a lambda function - e.g. dynamodb resource)

@konstantinlois
Copy link

konstantinlois commented Oct 12, 2021

I would also be happy to see a solution for this.
Especially because of this. But also because it's extra work to exclude the OPTIONS requests from auth.

Right now I am using a generic function which responds to OPTIONS requests with a 200 and the necessary CORS headers. Sadly I cannot use /{proxy+} for that function (I tried it) so I have to add all my functions paths to the events section one by one. To me that seems like a bit of overhead.

Thanks in advance.

@rambabusaravanan
Copy link

How do I define the sam template to exclude ApiKeyRequired: true for OPTIONS.

"OPTIONS request is mostly meant for browsers and invoked by browsers and browsers doesn't send any extra headers."

When we set api key as true, why does aws sam expects the api key for options too.
Why does sam missing the basics?

This issue is open for more than a year. Any progress on this?
@mndeveci

@rambabusaravanan
Copy link

@aahung @CoshUS @wchengru Any updates on this?

Problem: We use ApiKey in REST ApiGateway and when we automate using SAM with ApiKeyRequired: true, it sets ApiKey: true for OPTIONS also. As no browser will send any header for OPTIONS request, the apis we created is not consumable by client.

Due to this blocking issue, we're unable to use SAM to proceed further and our company asked us to use alternate. But I feel it would be good if we can proceed with SAM.

Please help on this blocking issue.

@wasilewicz
Copy link

I was struggling with this issue for 3 days...
This solutions works for me: https://stackoverflow.com/a/60925594

  1. Define additional event for OPTIONS method and disable ApiKeyRequired.
  2. Remember about returning proper CORS headers in lamba response
  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: Prod
      Auth:
        ApiKeyRequired: true
  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: ./
      Handler: MyFunctionHandler
      Runtime: dotnetcore3.1
      MemorySize: 256
      Policies:
        - "AWSLambdaBasicExecutionRole"
      Events:
        RootGet:
          Type: Api
          Properties:
            RestApiId: !Ref MyApi
            Path: /my_function
            Method: get
        RootOptions:
          Type: Api
          Properties:
            RestApiId: !Ref MyApi
            Path: /my_function
            Method: options
            Auth:
              ApiKeyRequired: false

@mrsan22
Copy link

mrsan22 commented Jun 6, 2022

This solution worked for me:
#1514 (comment)

@ckabalan
Copy link

I agree this is broken functionality. There is no scenario where auth works on an OPTIONS request and so should be omitted (with a note in the docs) from the final deployment.

I was able to work around this in a different way:

API Definition... I commented out or removed ApiKeyRequired from the Auth section...

API:
  Type: AWS::Serverless::Api
  Properties:
    StageName: v1
    Auth:
      #ApiKeyRequired: True
      UsagePlan:
        [ --- SNIP --- ]
    Cors:
      AllowMethods: [ --- SNIP --- ]
      AllowHeaders: [ --- SNIP --- ]
      AllowOrigin: [ --- SNIP --- ]

And then for each function event I added the ApiKeyRequired: true Auth option:

MyFunction:
  Type: AWS::Serverless::Function
  Properties:
    [ --- SNIP --- ]
    Events:
      ApiEvent:
        Type: Api
        Properties:
          Path: /mypath
          Method: get
          RestApiId: !Ref 'API'
          Auth:
            ApiKeyRequired: true
    [ --- SNIP --- ]

This resulted in the following in the console:

MyPath OPTIONS Auth

Basically the best way to do this is not to enforce ApiKeyRequired at the API layer but enforce it per Path+Method. After all the documentation does say (emphasis mine):

If set to true then an API key is required for all API events. For more information about API keys see Create and Use Usage Plans with API Keys in the API Gateway Developer Guide.

My feedback to the maintainers is the following:

  • Make ApiKeyRequired at the API-level exclude OPTIONS requests
  • Update the documentation to say "... API key is required for all API events with the exception of OPTIONS requests."

@hoffa
Copy link
Contributor

hoffa commented Mar 17, 2023

#2981 merged; will roll out over coming weeks.

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