Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 836
Jan Avatar asked Dec 10 '22 23:12

Jan


2 Answers

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(GE/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)
    }
like image 53
nirvana124 Avatar answered Jan 04 '23 17:01

nirvana124


What solved it for me was adding the following to my template.yaml:

Globals:
    Api:
        Cors:
            AllowMethods: "'GET,POST,OPTIONS'"
            AllowHeaders: "'content-type'"
            AllowOrigin: "'*'"
            # AllowCredentials: true  Uncomment only if you choose a specific origin instead of the * wildcard.

And just like nirvana124 and Nitesh said, you also need to return these headers with the response in each endpoint:

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)
}
like image 33
isaacsan 123 Avatar answered Jan 04 '23 15:01

isaacsan 123