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

How do I enable CORS? #1955

Closed
Jorenm opened this issue Aug 24, 2016 · 64 comments
Closed

How do I enable CORS? #1955

Jorenm opened this issue Aug 24, 2016 · 64 comments

Comments

@Jorenm
Copy link

@Jorenm Jorenm commented Aug 24, 2016

Serverless Framework Version: 1.0.0-beta.1.1

How do I enable CORS so I can access my functions? I can't find anything in the docs, and the CORS plugin seems to not be relevant to the current version of Serverless.

@Jorenm
Copy link
Author

@Jorenm Jorenm commented Aug 24, 2016

Digging through the docs I finally managed to find this: https://github.com/serverless/serverless/tree/master/lib/plugins/aws/deploy/compile/events/apiGateway

Sadly, it does not work. For GET requests it seems fine, but for POST it doesn't work.

@ac360
Copy link
Member

@ac360 ac360 commented Aug 25, 2016

Hi all. We are restructuring our docs to make this easier to find.

@Jorenm could you please post more info on your issue so we can verify the error is on our end?

@Jorenm
Copy link
Author

@Jorenm Jorenm commented Aug 25, 2016

Here is my serverless.yml config for it:

functions:
  createUser:
    handler: handler.createUser
    events:
      - http:
          path: user/create
          method: post
          cors: true
  getUser:
    handler: handler.getUser
    events:
      - http:
          path: user/load
          method: get
          cors: true

I can confirm when I go to the API Gateway that it is setting up OPTIONS functions, and configuring both end points with the same CORS-related settings.

I'm trying to access them like this:

$.ajax({
    url: 'https://rq6odooeo8.execute-api.us-west-2.amazonaws.com/dev/user/load',
    method: 'get',
    crossDomain: true,
    data: {id: clientId}
}).done(function(response) {
    console.log(response);
});

$.ajax({
    url: 'https://rq6odooeo8.execute-api.us-west-2.amazonaws.com/dev/user/create',
    method: 'post',
    crossDomain: true,
    data: {id: clientId}
}).done(function(response) {
    console.log(response);
});

The GET one works, the POST one throws this error:

XMLHttpRequest cannot load https://rq6odooeo8.execute-api.us-west-2.amazonaws.com/dev/user/create. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:5200' is therefore not allowed access. The response had HTTP status code 400.

If you'd like details about any of the API Gateway settings, let me know.

@ac360
Copy link
Member

@ac360 ac360 commented Aug 25, 2016

@Jorenm Can you confirm you are adding this header and it's still not working? I just tested your endpoint (sorry) with that Header and it works.

Content-Type: application/json

@Jorenm
Copy link
Author

@Jorenm Jorenm commented Aug 25, 2016

I just tested your endpoint (sorry)

Heh, no problem. If I minded I'd have edited it out :P

Content-Type: application/json

Adding this did indeed fix it. I haven't done any CORS stuff before, so maybe this is obvious to most people. If it isn't obvious, putting a sample AJAX request in the CORS section might be good?

Thanks for your help!

@Jorenm Jorenm closed this Aug 25, 2016
@ac360
Copy link
Member

@ac360 ac360 commented Aug 25, 2016

@Jorenm Thanks. I think the issue is we need to have better docs. People run into this problem w/ Angular too.

Let us know how else we can help. We're here full-time and we have LOTS coming :)

@pmuens
Copy link
Contributor

@pmuens pmuens commented Aug 25, 2016

We're just discussing the new docs structure here. @Jorenm Would be great if you could give some feedback on that #1957

@lakinducker
Copy link

@lakinducker lakinducker commented Dec 10, 2016

Hi Serverless Team,

I really like serverless! I was able to quickly get a couple of API's running. I, unfortunately, am having a CORS problem with the API's and Angular 2.

XMLHttpRequest cannot load https://s7t6o3hx8l.execute-api.us-east-1.amazonaws.com/dev/notes. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access.

I using the { 'Content-Type': 'application/json' } in the header for my GET from Angular. Also I know that I had cors: true in my serverless.yml. I checked the CORS Headers in the AWS API Gateway for GET method for the notes resource. They are the following:
Access-Control-Allow-Headers 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'
Access-Control-Allow-Methods 'OPTIONS,GET,POST'
Access-Control-Allow-Origin '*'

Still I cannot get this to work. Usually I develop REST API's with Node.js and Express. I use the CORS node.js package to enable CORS. With this I have never had the issue described above.

I am sure that there is something I am just missing. I really appreciate your help and want to do a lot more with serverless. Thank you!

@pmuens
Copy link
Contributor

@pmuens pmuens commented Dec 10, 2016

@lakinducker thanks for the question.
Could you paste your serverless.yml here real quick?

In the meantime you might also want to take a look at the docs about CORS setup: https://serverless.com/framework/docs/providers/aws/events/apigateway#enabling-cors

@lakinducker
Copy link

@lakinducker lakinducker commented Dec 10, 2016

service: note-rest-api

frameworkVersion: ">=1.1.0 <2.0.0"

provider:
  name: aws
  runtime: nodejs4.3
  iamRoleStatements:
    - Effect: Allow
      Action:
        - dynamodb:DescribeTable
        - dynamodb:Query
        - dynamodb:Scan
        - dynamodb:GetItem
        - dynamodb:PutItem
        - dynamodb:UpdateItem
        - dynamodb:DeleteItem
      Resource: "arn:aws:dynamodb:us-east-1:*:*"

functions:
  create:
    handler: notes/create.create
    events:
      - http:
          path: notes
          method: post
          cors: true

  list:
    handler: notes/list.list
    events:
      - http:
          path: notes
          method: get
          cors: true

  get:
    handler: notes/get.get
    events:
      - http:
          path: notes/{id}
          method: get
          cors: true

  update:
    handler: notes/update.update
    events:
      - http:
          path: notes/{id}
          method: put
          cors: true

  delete:
    handler: notes/delete.delete
    events:
      - http:
          path: notes/{id}
          method: delete
          cors: true

resources:
  Resources:
    NotesDynamoDbTable:
      Type: 'AWS::DynamoDB::Table'
      DeletionPolicy: Retain
      Properties:
        AttributeDefinitions:
          -
            AttributeName: id
            AttributeType: S
        KeySchema:
          -
            AttributeName: id
            KeyType: HASH
        ProvisionedThroughput:
          ReadCapacityUnits: 1
          WriteCapacityUnits: 1
        TableName: 'notes'

@lakinducker
Copy link

@lakinducker lakinducker commented Dec 10, 2016

Is it a problem that the indents where lost in pasting it?

@pmuens
Copy link
Contributor

@pmuens pmuens commented Dec 10, 2016

@lakinducker Thanks
No problem! I updated your comment with the corresponding markdown and now the indentation is back.

You're using the LAMBDA-PROXY integration which means that your response needs the Access-Control-Allow-Origin header.

Here's an example how this looks like (taken from the docs):

'use strict';

exports.handler = function(event, context, callback) {

    const response = {
      statusCode: 200,
      // HERE'S THE CRITICAL PART
      headers: {
        "Access-Control-Allow-Origin" : "*" // Required for CORS support to work
      },
      body: JSON.stringify({ "message": "Hello World!" })
    };

    callback(null, response);
};

@lakinducker
Copy link

@lakinducker lakinducker commented Dec 10, 2016

That worked! It is really great seeing this working with Angular 2. I made the mistake of not including the

headers: {
  "Access-Control-Allow-Origin" : "*" // Required for CORS support to work
}

in my Lambda functions. I won't make that mistake again. Learn something every day. I really appreciate your help!

@pmuens
Copy link
Contributor

@pmuens pmuens commented Dec 11, 2016

@lakinducker great to hear that this fixed your problem! 🎉

We're happy to help! Just let us know if you have any problems / need help! 👍

@TimothyDalbey
Copy link

@TimothyDalbey TimothyDalbey commented Dec 20, 2016

I tried to delete a stack and redeploy it (for a variety of reasons, none of which fit within the context of this discussion) and was getting the same error message. With a little investigation I determined that the reason for the error was that the original Cloudformation delete was not successful (I had done some manual bootstrapping after an initial deployment which is why the delete was not working...)

Once I manually deleted the Stack to success, the deploy method worked fine.

@reddhouse
Copy link

@reddhouse reddhouse commented Feb 22, 2017

Hi Team Serverless. Thanks for your great framework! I followed your YouTube tutorials "Building a REST API with Lambda & DynamoDB", and my requests/responses are working fine from the terminal (with curl). However, when I try the same 'get' from inside my locally hosted Vue/Webpack app (using the axios library), I'm getting the same error that @lakinducker mentioned above:

XMLHttpRequest cannot load https://thgc79u8ol.execute-api.us-east-1.amazonaws.com/dev/todos. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.

I tried all of the suggestions above, including setting the Access-Control-Allow-Origin to '*' inside of both the list.js and get.js handlers, and also giving axios the following configuration in my app's get request:

headers: { 'Content-Type': 'application/json' }

Still, no luck. Any ideas?

@pmuens
Copy link
Contributor

@pmuens pmuens commented Feb 23, 2017

Hey @reddhouse thanks for the kind words!

We've open sourced have a fully fledged Serverless application called "Scope" recently. You can see the source code here: https://github.com/serverless/scope

It integrates the backend and frontend.

The serverless.yml with CORS setup can be found here: https://github.com/serverless/scope/blob/master/backend/serverless.yml

@fregante
Copy link
Contributor

@fregante fregante commented Mar 10, 2017

Dumb question: if I have to manually add this to the response:

      headers: {
        "Access-Control-Allow-Origin" : "*" // Required for CORS support to work
      },

What does cors: true do?

  get:
    handler: notes/get.get
    events:
      - http:
          path: notes/{id}
          method: get
          cors: true ///<---

@kiwifellows
Copy link

@kiwifellows kiwifellows commented Mar 12, 2017

@bfred-it the cors:true adds support on the API Gateway side, not in the Lambda function itself. Also the documentation for serverless states that cors: true does the following:

cors:
            origins:
              - '*'
            headers:
              - Content-Type
              - X-Amz-Date
              - Authorization
              - X-Api-Key
              - X-Amz-Security-Token
            allowCredentials: false

See https://serverless.com/framework/docs/providers/aws/events/apigateway/

@ithinco
Copy link

@ithinco ithinco commented Mar 30, 2017

@kiwifellows I encountered the same issue as @reddhouse ,also tried all of the suggestions above, and looked at the source code of Scope.

Just don't know where I got wrong.:(

@pmuens
Copy link
Contributor

@pmuens pmuens commented Mar 30, 2017

@ithinco could you please share your serverless.yml and handler file so that we can take a look at it? Thanks!

@ithinco
Copy link

@ithinco ithinco commented Mar 31, 2017

There is no need to.:P

  1. add headers to all of the responses of aws-node-rest-api-with-dynamodb in the examples repo,
// create a response
    const response = {
      headers: {
        "Access-Control-Allow-Origin" : "*",
      },
      statusCode: 200,
      body: JSON.stringify(result.Item),
    };

2.deployed aws-node-rest-api-with-dynamodb in the examples repo to aws
3. enable cors
qq20170331-091954
4. curl https://ahhwlczx6f.execute-api.us-east-1.amazonaws.com/dev/todos
got []
5.

$.ajax({
	  url: 'https://ahhwlczx6f.execute-api.us-east-1.amazonaws.com/dev/todos',
	  method: 'get',
	  crossDomain: true,
	  data: '',
	  contentType: 'application/json',
	  headers: {
      "Access-Control-Allow-Origin" : "*",
    },
	}).done(function(response) {
	    console.dir(response);
	});

got error in the browser console

XMLHttpRequest cannot load https://ahhwlczx6f.execute-api.us-east-1.amazonaws.com/dev/todos. Request header field Access-Control-Allow-Origin is not allowed by Access-Control-Allow-Headers in preflight response.

the network log

General
Request URL:https://ahhwlczx6f.execute-api.us-east-1.amazonaws.com/dev/todos
Request Method:OPTIONS
Status Code:200 
Remote Address:54.230.213.96:443

Response Headers
access-control-allow-credentials:false
access-control-allow-headers:Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token
access-control-allow-methods:OPTIONS,GET,POST
access-control-allow-origin:*
content-length:0
content-type:application/json
date:Fri, 31 Mar 2017 01:18:05 GMT
status:200
via:1.1 7a87f44170a64ca50a528a4a5e5a1b16.cloudfront.net (CloudFront)
x-amz-cf-id:3STMXMdg3WUb3EatZQghvxeD45hLpnm2U2P-V9DcPVQHRqN3hnHpnQ==
x-amzn-requestid:e43aacb6-15af-11e7-9e7e-af7a8ba2ce01
x-cache:Miss from cloudfront

Request Headers
:authority:ahhwlczx6f.execute-api.us-east-1.amazonaws.com
:method:OPTIONS
:path:/dev/todos
:scheme:https
accept:*/*
accept-encoding:gzip, deflate, sdch, br
accept-language:zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4
access-control-request-headers:access-control-allow-origin, content-type
access-control-request-method:GET
origin:http://localhost:3001
referer:http://localhost:3001/
user-agent:Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36

@pmuens @kiwifellows

Update:

I see where I got wrong.

In the request headers.
access-control-request-headers:access-control-allow-origin, content-type

In the response headers.
access-control-allow-headers:Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token

no access-control-allow-origin.

I deleted it from jquery options, it works in the browser!

@pmuens
Copy link
Contributor

@pmuens pmuens commented Mar 31, 2017

@ithinco thanks for sharing! Nice to hear that the problem was resolved.

@algera
Copy link

@algera algera commented Apr 6, 2017

Hmm, I appear to be stuck on getting an API to respond using CORS. Following the documentation as well as this thread, I am unable to receive a valid response from API Gateway. The error seems to be coming from the OPTIONS endpoint which gets automatically created when deploying.

Here is some relevant information, any help would be much appreciated. cc: @pmuens @ithinco

Serverless Version

sls --version
1.10.2

Received Error:

OPTIONS https://XXXXXXXXXX.execute-api.us-east-1.amazonaws.com/v1/artists 403 ()
dispatchXhrRequest @ xhr.js:175
xhrAdapter @ xhr.js:12
dispatchRequest @ dispatchRequest.js:52
localhost/:1 XMLHttpRequest cannot load https://XXXXXXXXXX.execute-api.us-east-1.amazonaws.com/v1/artists. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 403.

Network Monitor

Request URL:https://XXXXXXXXXX.execute-api.us-east-1.amazonaws.com/v1/artists
Request Method:OPTIONS
Status Code:403 
Remote Address:52.84.239.157:443

Response Headers
content-length:23
content-type:application/json
date:Wed, 05 Apr 2017 23:56:54 GMT
status:403
via:1.1 a699d70234678d4cbb0dd9xxxxxxxxxx.cloudfront.net (CloudFront)
x-amz-cf-id:I25_rqa-sTOST8LHZED2NkKrz7_lWDm8w8c1yhNNbBxxxxxxxxxxxx==
x-amzn-errortype:ForbiddenException
x-amzn-requestid:8b7b50a7-1a5b-11e7-ac26-7f123301b7e8
x-cache:Error from cloudfront

Request Headers
:authority:XXXXXXXXXX.execute-api.us-east-1.amazonaws.com
:method:OPTIONS
:path:/v1/artists
:scheme:https
accept:*/*
accept-encoding:gzip, deflate, sdch, br
accept-language:en-US,en;q=0.8
access-control-request-headers:access-control-allow-origin, authorization, content-type, x-amz-date, x-amz-security-token
access-control-request-method:GET
cache-control:no-cache
dnt:1
origin:http://localhost:3000
pragma:no-cache
referer:http://localhost:3000/
user-agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36

Serverless Configuration (relevant pieces)

custom:
  versionPath: v1
  cors: true

functions:
  artists-read:
    handler: artist/readArtists.handler
    events:
      - http:
          path: ${self:custom.versionPath}/artists
          method: get
          cors: ${self:custom.cors}

resources:
  Resources:
    ApiGatewayMethodV1ArtistsGet:
      Type: "AWS::ApiGateway::Method"
      Properties:
        AuthorizationType: AWS_IAM

Lambda response code

(although I do not think it gets this far)

const response = {
  "statusCode": statusCode,
  "headers": {
        "Access-Control-Allow-Origin" : "*", // Required for CORS support to work
        "Access-Control-Allow-Credentials" : true, // Required for cookies, authorization headers with HTTPS 
        "Content-Type": "application/json"
  },
  "body": JSON.stringify(data)
};
this.context.succeed(response);

Front-end request

    var headers = {
      headers: {
        "Access-Control-Allow-Origin" : "*"
      }
    };  
    var apigClient = apigClientFactory.newClient(config);
    const request = apigClient.invokeApi(params, pathTemplate, method, headers, body);

@Andriy-Kulak
Copy link

@Andriy-Kulak Andriy-Kulak commented Apr 10, 2017

I followed all the instructions above and I still get the CORS error when I try to do a Post request. The request works well when I tested it locally but CORS shows up when I deploy to AWS. Any suggestions??

I tried the following multiple times after ensuring lambda function works locally (via serverless-offline)

  • added cors for my function in serverless.yml.
  • added the header to response in my handler
  • deploy to AWS
module.exports.upload = (event, context, callback) => {
...
      const response = {
        statusCode: 200,
        headers: {
            "Access-Control-Allow-Origin" : "*" // Required for CORS support to work
          },
        body: {
          "data" : "test123"
        }
      };
      callback(null, response);

my serverless.yml

functions:
  hello:
    handler: functions/upload/handler.upload
    events:
      - http:
          path: upload
          method: post
          cors: true

My front-end code is a simple axios POST request which has been working well in regular node/express environment

  axios.post(UPLOAD_URL, imageData)
    .then((response) => {
      // If request is good...
      console.log('PASS', response);
    }, (err) => {
      console.log('error', err);
    })
    .catch((err) => {
      console.log('error Catch', err);
    });

@pmuens
Copy link
Contributor

@pmuens pmuens commented Apr 24, 2017

@Andriy-Kulak the CORS settings look good. Nothing wrong there as far as I can tell. Have you tried to do a request with a different tool / e.g. looked into it with the developer tools of your browser?

Otherwise you could try to use the LAMBDA integration type:

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          integration: LAMBDA
          path: hello
          method: get
          cors: true
'use strict';

module.exports.hello = (event, context, callback) => {
  callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event });
};

@dashmug
Copy link
Contributor

@dashmug dashmug commented May 29, 2017

I'm having this problem with one project that uses lambda-proxy. I have another project that uses integration: lambda and CORS is working fine. But for these two, I can't get it to work.

The request works properly in Postman and the response headers already include Access-Control-Allow-Origin as you can see below.

screen shot 2017-05-29 at 5 39 31 pm

However, it still fails on the browser.

serverless.yml

events:
      - http:
          path: "/graphql"
          method: get
          authorizer: ${self:custom.authorizer}
          cors: true

@pmuens
Copy link
Contributor

@pmuens pmuens commented May 29, 2017

@dashmug thanks for commenting. What error message does your browser return?

We're currently fixing a CORS W3C incompatibility in #3692

@quantuminformation
Copy link
Contributor

@quantuminformation quantuminformation commented Sep 9, 2017

So I've added this to my lambda:

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

with

functions:
  sendMail:
    handler: lambda/mailServices.sendMail
    events:
        - http:
            path: sendMail
            method: post
            cors: true

and in the front end I do:

    fetch('https://216z7mamc7.execute-api.eu-west-2.amazonaws.com/dev/sendMail', {

      method: 'POST',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
      },

      body: JSON.stringify(body)
    })

Is it correct, I'm getting No 'Access-Control-Allow-Origin' header is present on the requested resource. from the backend

I tried mode: 'cors',
and
type: 'cors',
with fetch but still no luck

@pmuens
Copy link
Contributor

@pmuens pmuens commented Sep 10, 2017

Thanks for commenting @quantuminformation 👍

Could you post the code of your Lambda function? Does your code look smth. like this?

@joshisimt
Copy link

@joshisimt joshisimt commented Sep 11, 2017

Hi @pmuens ,

I am using Angular 2 , keycloak and spring boot.

In case of redirecting from angular2 to keycloak page and getting same error-
XMLHttpRequest cannot load http://localhost:9090/auth/realms/paydbackend/protocol/openid-connect/auth?…roducts&state=3543d363-9c94-462c-afaf-052277353f9f&login=true&scope=openid. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.

From the angular code I am doing following call-
getProducts() { return this.http.get('/api/products') .map((res:Response) => res.json()).subscribe(profile => this.profile = profile); }

Also tried this one
` getProducts() {
let headers = new Headers({ 'Access-Control-Allow-Origin': '*','Access-Control-Allow-Credentials':'true' });

return this.http.get('/api/products',headers)
            .map((res:Response) => res.json()).subscribe(profile => this.profile = profile);

}
`

Backend /api/prodcts is secured by keycloak.

I have also added web origins property to * in keycloak configuration but still no luck.

Can you please help?

Thanks

@quantuminformation
Copy link
Contributor

@quantuminformation quantuminformation commented Sep 11, 2017

I resolved it, I added

headers: {
'Access-Control-Allow-Origin': '*', // Required for CORS support to work
'Access-Control-Allow-Credentials': true, // Required for cookies, authorization headers with HTTPS
},
but was still getting a similar error, but the lambda was being called, it was an issue with my node code.

thanks

@pmuens
Copy link
Contributor

@pmuens pmuens commented Sep 11, 2017

@quantuminformation thanks for sharing. Glad to hear that you were able to resolve the problem 👍

@joshisimt
Copy link

@joshisimt joshisimt commented Sep 11, 2017

Can you please help on above ?

@dashmug
Copy link
Contributor

@dashmug dashmug commented Sep 11, 2017

@joshisimt
What does your lambda function return?
Have you read this page?
Are you using Lambda Proxy Integration or Lambda Integration?
Have you added headers as well?

e.g.

{
    'Access-Control-Allow-Origin': '*', // Required for CORS support to work
}

@joshisimt
Copy link

@joshisimt joshisimt commented Sep 11, 2017

@dashmug I am not using either Lambda integration or Lambda Proxy Integration.

@dashmug
Copy link
Contributor

@dashmug dashmug commented Sep 11, 2017

@joshisimt What are you using then? Please provide more information.

Even better, try using https://gitter.im/serverless/serverless to ask for help.

@prestontighe
Copy link
Contributor

@prestontighe prestontighe commented Oct 4, 2017

Idea: Here is another reason I ran into not receiving the CORs headers. I found that you won't receive headers on your requests that get returned by the default AWS API Gateway responses. You can manually set the headers on the default responses for your gateway in the AWS console. I don't know if you can set these in the Serverless config or not.

Example: I was running a 30+ second Lambda function that was returning a 504 Integration timeout. The response was coming back from API gateway without the cors headers. I had all the cors header correct in code like most people have said in this thread.

Solution: get the response down below 10 seconds because 30 seconds is a hard cap for API gateway and can't be increased.

@thesolotraveller
Copy link

@thesolotraveller thesolotraveller commented Oct 5, 2017

@pmuens Thanks a lot. Got the CORS issue with serverless resolved.
Awesome.

@gabrielkaputa
Copy link

@gabrielkaputa gabrielkaputa commented Oct 10, 2017

Hi,

I had the same issue with cors. I'm using lambda-proxy, the headers in the response are set, cors: true was also set but i still had the issue with missing Access-Control-Allow-Origin header. I solved it by removing authorizer: aws_iam from serverless.yml from the function. Is it a good way to solve it? The API worked just fine from everywhere else, except the browser.

@flameoftheforest
Copy link

@flameoftheforest flameoftheforest commented Nov 15, 2017

Hi,

Here's my serverless.yml

custom:
  allowed-headers:
    - Content-Type
    - X-Amz-Date
    - Authorization
    - X-Api-Key
    - X-Amz-Security-Token
    - X-Amz-User-Agent
    - X-Cowabunga
functions:
  Registration:
    handler: ArmaBackending::Backckending.MahAPI::Register
    role: superSpecialRole
    events:
      - http:
          path: sillyputty
          method: post
          cors:
            origin: "*"
            headers: ${self:custom.allowed-headers}
            allowCredentials: true
  RetrieveDetails:
    handler: ArmaBackending::Backckending.MahAPI::Details
    role: superSpecialRole
    events:
      - http:
          path: sillyputty/puttysilly
          method: get
          request:
            parameters:
              paths:
                type: true
          cors:
            origin: "*"
            heanders: ${self:custom.allowed-headers}
            allowCredentials: true
  • For POST [URL]/sillyputty, the CORS OPTIONS preflight returns the correct access-control-request-headers specified in the self:custom.allowed-headers. i. e.: Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent,X-Cowabunga
  • However, GET [URL]/sillyputty/puttysilly, the CORS OPTIONS preflight returns the default Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent
  • I can observe the Header Mappings exhibiting the above in Access-Control-Allow-Headers in API-Gateway Dashboard.

Can someone help me to understand what I did wrong?

Thank you very much!

@saurshaz
Copy link

@saurshaz saurshaz commented Nov 18, 2017

@flameoftheforest & others Lambda shall contain the cors allowance headers as listed in https://github.com/serverless/serverless/issues/4037 . Nothing on client side shall matter much

@kiwifellows
Copy link

@kiwifellows kiwifellows commented Nov 20, 2017

Hi guys,
Just a note related to this error.

I noticed the browser will sometimes get a CORS error when I had my UI talking to the back end serverless API. I realsied the issue wasn't actually the configuration in Serverless itself but was an issue when a particular Lambda function crashed / 500/403 error. When this happens behind API Gateway, if you don't have a handler in Lambda to handle an error and put out a response then a 500 error or 403 access denied error will occur causing the browser to think that CORS is not enabled...

Hope that helps.

cheers,

Ben

@mocon
Copy link

@mocon mocon commented Jan 29, 2018

Thank you @pmuens!

@ozbillwang
Copy link

@ozbillwang ozbillwang commented Apr 18, 2018

I have same issue as #1955 (comment)

@pmuens 's solution is helpful for any http calls with lambda function, but in my case, I use http-proxy integration, which doesn't need lambda function.

I try to add headers in serverelss.yml, but don't fix this issue.

      cors:
        origins:
          - "*"
        headers:
          - Content-Type
          - X-Amz-Date
          - Authorization
          - X-Api-Key
          - X-Amz-Security-Token
          - X-Amz-User-Agent
          - Access-Control-Allow-Headers
          - Access-Control-Allow-Origin
          - Access-Control-Allow-Methods

anything else I can do?

updates

Above setting works in fact.

@leantide
Copy link

@leantide leantide commented May 6, 2018

Having cors:true and the Access-Control-Allow- headers described in the thread, it turns out that I was getting the cors issue because I was running on nodejs 8.10 (now supported by AWS) and not on nodejs 6.10 (older version still supported by AWS).

@ozbillwang
Copy link

@ozbillwang ozbillwang commented May 7, 2018

@leantide

Does serverless framework formally support nodejs 8.10 already? Any official document about it?

@mithunph
Copy link

@mithunph mithunph commented Mar 16, 2019

@lakinducker great to hear that this fixed your problem! 🎉

We're happy to help! Just let us know if you have any problems / need help! 👍

Hi @lakinducker,
I am using express integrated in serverless framework. Most of the times API's return 502 bad gateway error and it will get fixed automatically after certain amount of time. How do i Fix this ?
Below is my serverless.yml file
provider:
name: aws
runtime: nodejs8.10
memorySize: 128 # set the maximum memory of the Lambdas in Megabytes
timeout: 10 # the timeout is 10 seconds (default is 6 seconds)
stage: ${opt:stage, 'local'} # setting the env stage to dev, this will be visible in the routes
region: ap-south-1
environment:
DB: ${file(./config.${self:provider.stage}.json):DB}
STAGE: ${file(./config.${self:provider.stage}.json):environment}

functions:
server:
handler: server.run
events:
- http: ANY /
- http: 'ANY {proxy+}'

@dm-grinko
Copy link

@dm-grinko dm-grinko commented Mar 28, 2019

If you can't find good solution make sure you use correct http method and http url

@rudyhadoux
Copy link

@rudyhadoux rudyhadoux commented May 18, 2019

Hi,
Serverless should update https://github.com/serverless/examples/tree/master/aws-node-rest-api-with-dynamodb with :

  1. headers: {'Access-Control-Allow-Origin': '*','Access-Control-Allow-Credentials': true}
  2. runtime: nodejs8.10 in serverless.yml.

@colketo
Copy link

@colketo colketo commented Jun 6, 2019

[Serverless users] I lost a complete day trying to debug the same issue and reading the excellent serverless-stack tutorial I found THE problem.

A 403 error is related to API Gateway and no to CORS.

Solution:
Don't forget config how your serverless app handles gateway error.

You can follow this guide to fix the 403 error (then CORS issue)

https://serverless-stack.com/chapters/handle-api-gateway-cors-errors.html

Hope helps you guys!

@dimadk24
Copy link

@dimadk24 dimadk24 commented Nov 17, 2019

Dumb question: if I have to manually add this to the response:

      headers: {
        "Access-Control-Allow-Origin" : "*" // Required for CORS support to work
      },

What does cors: true do?

  get:
    handler: notes/get.get
    events:
      - http:
          path: notes/{id}
          method: get
          cors: true ///<---

@fregante and whoever interested why we need to configure cors headers both in serverless.yml and inside actual lambda function handler, see this article from serverless. It clearly explains it.

TL;DR:
because of the OPTIONS preflight request.

See also https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

@guilherme90
Copy link

@guilherme90 guilherme90 commented Sep 2, 2020

For anyone who is having this problem. In my case the parameter cors: true did not work! If you are using Api Gateway and the type is LAMBDA_PROXY, you must make the following settings:

serverless.yml

endpoint-name:
    handler: func.handler
    events:
      - http:
          path: my-endpoint
          method: post
          cors:
            origins: '*' # <-- Attention here...

Response

{
  statusCode: 200,
  headers: {
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Credentials': false
  },
  body: JSON.stringify({
    message: 'Ok'
  })
}

I hope this helps!!

@Gildissimo
Copy link

@Gildissimo Gildissimo commented Nov 12, 2020

Hi, I've got a problem

in my serverless.yml
apptest:
handler: app.hello
events: #Define the events that trigger the lambda

  • httpApi:
    path: /test
    method: GET
    authorizer: serviceAuthorizer
    cors: true

then in my app.js I've

...

module.exports.hello = function(event, context, callback) {
// const response = {
// statusCode: 200,
// headers: {
// 'Access-Control-Allow-Origin': '*', // Required for CORS support to work
// 'Access-Control-Allow-Credentials': true, // Required for cookies, authorization headers with HTTPS
// },
// body: JSON.stringify({ message: 'Hello World!' }),
// };

// callback(null, response);

const response = {
statusCode: 200,
// HERE'S THE CRITICAL PART
headers: {
"Access-Control-Allow-Origin" : "*", // Required for CORS support to work
"Access-Control-Allow-Credentials" : true, // Required for cookies, authorization headers with HTTPS
"Content-Type": "application/json"
},
body: JSON.stringify({ "message": "Hello World!" })
};

callback(null, response);

};

BUT When I call via postman I receive obviously "Hello World!" in body, but only this response headers

Date: Thu, 12 Nov 2020 17:09:22 GMT
Content-Type: application/json
Content-Length: 26
Connection: keep-alive
Apigw-Requestid: V53aPjEHFiAEJ2g=

WHYYYYYYYYYYYYYYY???

@mithundas79
Copy link

@mithundas79 mithundas79 commented Nov 26, 2020

Hi - I am using the following version of serverless for my lambda project

Framework Core: 1.78.1
Plugin: 3.7.0
SDK: 2.3.1
Components: 2.34.5

I have following in the serverless.yml

  AdminTokenVerify: 
    handler: src/handlers/Admins/auth.auth
  AdminLogin:
    handler: src/handlers/Admins/auth.login
    memorySize: 3008
    timeout: 15
    events:
      - http:
          path: admins/login
          method: post
          cors: true
  AdminRefreshToken:
    handler: src/handlers/Admins/auth.refreshToken
    memorySize: 3008
    timeout: 15
    events:
      - http:
          path: admins/refresh-token
          method: get
          cors: true
          authorizer: 
            name: AdminTokenVerify
            type: token

and in my handler I use

.then((response) => {
        return {
          statusCode: 200,
          headers: {
            'Access-Control-Allow-Origin': '*', // Required for CORS support to work
            'Access-Control-Allow-Credentials': true // Required for CORS support to work
          },
          body: JSON.stringify({
            isSuccess: true,
            data: {
              token: response.token,
              action: response.action
            },
            message: "Login message"
          }, null, 2)
        };
      })

the above example is for the return of the login handler. In the refsh token function return object the headers are the same.
I get response in POSTMAN but when i try with jquery in browser I get ->

Access to XMLHttpRequest at 'https://rmmsyr6o93f.execute-api.eu-central-1.amazonaws.com/dev/admins/login' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

My client code is following

$.ajax
    ({
        dataType: "json",
        method: "post",
        url: url,
        headers: {
            "Content-Type": "application/json"
        },
        data: {email: email, password: password},
        success: function(data) 
        {
            console.log("log response on success");
            console.log(data);
        },
        error: function(err) 
        {
            console.log("log response on error");
            console.log(err);
        }
    });

Also I read the below guide
https://www.serverless.com/blog/cors-api-gateway-survival-guide

And tried following in my sertverless.yml

resources:
  Resources:
    GatewayResponseDefault4XX:
      Type: 'AWS::ApiGateway::GatewayResponse'
      Properties:
        ResponseParameters:
          gatewayresponse.header.Access-Control-Allow-Origin: "'*'"
          gatewayresponse.header.Access-Control-Allow-Headers: "'*'"
        ResponseType: DEFAULT_4XX
        RestApiId:
          Ref: 'ApiGatewayRestApi'

But that gives me "Internal Error"

@diva-D
Copy link

@diva-D diva-D commented May 5, 2021

So I bashed my head trying to figure this out for hours - but finally got it to work. I was trying to access the API endpoints from my separately deployed Vue application but kept getting the CORS issue. It would work using Postman, but not from the application.

First I implemented the steps from this article: https://www.serverless.com/blog/cors-api-gateway-survival-guide

serverless.yml

functions:
  validate:
    handler: server/api/auth.validate
    events:
      - httpApi:
         path: /validate
         method: post
         cors: true // <--- add this

Then added this to my lambda function

return {
    statusCode: 201,
    headers: {
      'Access-Control-Allow-Origin': '*',          // <-----
      'Access-Control-Allow-Credentials': true,    // <-----
    },
  };

But I was still getting

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

Finally... I found this article: https://serverless-stack.com/chapters/handle-api-gateway-cors-errors.html

Explaining how to add a resource for a default Gateway Response that handles CORS issues and adds the correct response headers to handle the preflight request.

serverless.yml

resources:
  Resources:
    GatewayResponseDefault4XX:
      Type: 'AWS::ApiGateway::GatewayResponse'
      Properties:
        ResponseParameters:
          gatewayresponse.header.Access-Control-Allow-Origin: "'*'"
          gatewayresponse.header.Access-Control-Allow-Headers: "'*'"
        ResponseType: DEFAULT_4XX
        RestApiId:
          Ref: 'ApiGatewayRestApi'
    GatewayResponseDefault5XX:
      Type: 'AWS::ApiGateway::GatewayResponse'
      Properties:
        ResponseParameters:
          gatewayresponse.header.Access-Control-Allow-Origin: "'*'"
          gatewayresponse.header.Access-Control-Allow-Headers: "'*'"
        ResponseType: DEFAULT_5XX
        RestApiId:
          Ref: 'ApiGatewayRestApi'

Now it's all working as it should be. Hope that helps future people struggling.

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

Successfully merging a pull request may close this issue.

None yet