amazon-web-servicescorsaws-api-gatewayaws-saminfrastructure-as-code

How to enable CORS with AWS SAM


I'm trying to enable CORS in my AWS SAM app. Here is the snippet from my template.yaml:

Globals:
  Api:
    Cors:
      AllowMethods: "'*'"
      AllowHeaders: "'*'"
      AllowOrigin: "'*'"

Resources:
  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: prod
      Auth:
        Authorizers:
          MyCognitoAuthorizer: ...

  getByIdFunc:
    Type: AWS::Serverless::Function
    Properties:
      Handler: src/handler.handle
      Events:
        ApiEvent:
          Type: Api
          Properties:
            Path: /{id}
            Method: GET
            RestApiId: !Ref MyApi

According to this Using CORS with AWS SAM and that https://github.com/aws/serverless-application-model/issues/373, the cors config should work but unfortunately no header is set on the API response, as seen below.

< HTTP/2 200 
< content-type: application/json
< content-length: 770
< date: Tue, 13 Apr 2021 19:55:31 GMT
< x-amzn-requestid: ...
< x-amz-apigw-id: ...
< x-amzn-trace-id: Root=1-...-...;Sampled=0
< x-cache: Miss from cloudfront
< via: 1.1 ...cloudfront.net (CloudFront)
< x-amz-cf-pop: FRA2-C2
< x-amz-cf-id: ...==
< 
* Connection #0 to host ....execute-api.eu-central-1.amazonaws.com left intact
[{"model": ..}]

I also tried adding the cors config to the API definition (MyApi) itself like its stated in the offical docs here, but without success.

I could add the header in the response by myself but i rather have it in the template file.


Solution

  • Using SAM/CloudFormation or AWS Console you can setup CORS headers for OPTIONS method which will be called by browser before calling your actual API method(GET/POST etc). From postman or any other service only your endpoint will be called.

    When we are using lambda proxy with API Gateway we need to set the CORS headers in the response object from lambda.

    To enable CORS for the Lambda proxy integration, you must add Access-Control-Allow-Origin: domain-name to the output headers. domain-name can be * for any domain name.

    return {
            statusCode: 200,
            headers: {
                "Access-Control-Allow-Headers" : "Content-Type",
                "Access-Control-Allow-Origin": "*", // Allow from anywhere 
                "Access-Control-Allow-Methods": "GET" // Allow only GET request 
            },
            body: JSON.stringify(response)
        }