Eddie Martinez
Eddie Martinez

Reputation: 13910

Enable CORS when running AWS SAM CLI locally

Whenever I try to access serverless lambda function via POST through the browser I get the error

Response to preflight request doesn't pass access control check: No >'Access-Control-Allow-Origin' header is present on the requested resource.

When it is a /GET it works fine I have read it is because it is not sending pre flight request. When I change it to POST this is when it fails.

The command I am running:

sam local start-api

And my template.yaml is:

...

Resources:
    PropertiesFunction:
        Type: AWS::Serverless::Function
        Properties:
            CodeUri: target/service-0.0.1-SNAPSHOT.jar
            Handler: com.aws.PropertiesHandler::handleRequest
            Runtime: java8
            Events:
                PropertiesApi:
                    Type: Api
                    Properties:
                        Path: /properties
                        Method: post

...

How can I enable CORS on these endpoints?

Upvotes: 10

Views: 10835

Answers (5)

ADringer
ADringer

Reputation: 2834

Bit late to the party, but I've been struggling with this and found a solution. Hopefully will help someone else as well. I didn't want to polute my lambda code with additional, unsafe headers so looked into doing it within SAM.

I only use SAM for local development, not for deployment so this solution might not be for everyone as it requires changes to the template.

The solution to this is to use HttpApi in the SAM template instead of 'Api. I've added the following to the Globals section:

Globals:
  HttpApi:
    CorsConfiguration:
      AllowHeaders:
        - Content-Type
        - Authorization
        - Access-Control-Allow-Origin
      AllowMethods:
        - '*'
      AllowOrigins:
        - '*'

And then changed the Function resource to the HttpApi type:

MyFunction:
    Type: AWS::Serverless::Function 
    Properties:
      CodeUri: api/
      Handler: management.createHandler
      Runtime: nodejs20.x
      Architectures:
      - x86_64
      Events:
        HelloWorld:
          Type: HttpApi <-- Change here
          Properties:
            Path: /announcement
            Method: post

And now all responses when local start-api return the CORS headers.

One odd thing, I have many Functions defined in the template but I only had to change the Type on one of them to make the headers work for all.

Upvotes: 0

CyborgHead
CyborgHead

Reputation: 11

Try this on your serverless template file if you are using SAM

"Globals": {
    "Api": {
      "Cors": {
        "AllowMethods": "'POST, GET, PUT, DELETE'",
        "AllowHeaders": "'content-type'",
        "AllowOrigin": "'*'"
      }
    }
}

Upvotes: 0

ngoctrambui
ngoctrambui

Reputation: 141

I had the same error and I have already fixed it in 3 steps. (AWS Lambda in Java8, SAM CLI v0.37.0)

  1. Add options for your header:
    Map<String, String> headers = new HashMap<>();
    headers.put("Content-Type", "application/json");
    headers.put("X-Custom-Header", "application/json");
    headers.put("Access-Control-Allow-Origin", "*");
    headers.put("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, PATCH, DELETE");
    headers.put("Access-Control-Allow-Headers", "X-Requested-With,content-type");
  1. Add Option Cors into template.yaml
    Globals:
      Function:
        Timeout: 20
      Api:
        Cors:
          AllowMethods: "'GET,POST,OPTIONS'"
          AllowHeaders: "'content-type'"
          AllowOrigin: "'*'"
          AllowCredentials: "'*'"
  1. Update properties resource function in template.yaml
          Events:
            HelloWorld:
              Type: Api 
              Properties:
                # Path: /hello
                # Method: get
                Path: "/{proxy+}"
                Method: ANY

Upvotes: 13

me2resh
me2resh

Reputation: 886

First, you will need to add the following section in the template.yml to enable cors in the API gateway:

Globals:
  Api:
    Cors:
      AllowMethods: "'GET,POST,OPTIONS'"
      AllowHeaders: "'content-type'"
      AllowOrigin: "'*'"
      AllowCredentials: "'*'"

Then in your lambda function response


        MultivaluedMap<String, Object> headers = responseContext.getHeaders();

        headers.add("Access-Control-Allow-Origin", "*");
        headers.add("Access-Control-Allow-Headers", requestContext.getHeaderString("Access-Control-Request-Headers"));
        headers.add("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,HEAD,OPTIONS");

Upvotes: 6

user10682499
user10682499

Reputation: 41

You should be able to get around this for local testing by explicitly adding the following headers to your response, in your handler function:

    "Access-Control-Allow-Origin": "*"

You can use an environment variable that only adds the headers if you're running locally.

Here's a simple Python example from a handler function I have:

   if not all(field in values for field in required_fields):
    response = {
        'statusCode': 400,
        'body': json.dumps(
            {
                'message': 'Required data missing from request body'
            }
        )        
    }
    # explicitly add CORs headers for local testing
    response['headers'] = {"Access-Control-Allow-Origin": "*"}
    return response

This is only suitable for local testing, when you deploy to an API Gateway CORs is handled by configuration on the API Gateway.

This solution worked for me until I also added authorization to the API, with a Cognito user pool, which I'm currently trying to work through.

Here's a similar post on the issue: How to Enable CORS for an AWS API Gateway Resource

Here's reference to it in the official AWS documentation.

Upvotes: 4

Related Questions