API Gateway, blocked by CORS policy: No 'Access-Control-Allow-Origin' header - go

I know this question might be duplicated, but none of the existing question point to anything I'm not doing...
I've deployed an API using the serverless framework, but I'm having trouble with CORS.
I'm doing a get request using axios:
axios.get('https://test.execute-api.us-west-1.amazonaws.com/dev/test?from=2012-01-09T21:40:00Z')
.then(response => {
this.data = response.data;
})
.catch(error => console.log(error))
And I'm getting the following error:
Access to XMLHttpRequest at 'https://test.execute-api.us-west-1.amazonaws.com/dev/test?from=2012-01-09T21:40:00Z' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
What I've already done:
Made sure there's an OPTIONS method in API Gateway with a method response that looks like this:
Made sure I deployed those changes.
Also, the response of my Lambda function is returning the following headers:
return events.APIGatewayProxyResponse{
StatusCode: http.StatusOK,
Headers: map[string]string{
"Access-Control-Allow-Origin": "http://localhost:8080",
"Access-Control-Allow-Credentials": "true",
},
Body: string(jsonEvents),
}, nil
I also tried setting Access-Control-Allow-Origin to '*'
My serverless.yml file has cors: true on each of the function events:
functions:
deploymentFrequency:
handler: bin/update/deployment-frequency
events:
- http:
path: deployment-frequency
method: post
cors: true
fetchDeploymentFrequency:
handler: bin/fetch/deployment-frequency
events:
- http:
path: deployment-frequency
method: get
cors: true
What am I missing? Nothing seems to work. The request works fine from Postman and it looks to be including the headers, so this seems to be an issue with the OPTIONS method.

My configuration is:
(event, context, callback) => {
callback(null, {
statusCode: (code || 200),
body: JSON.stringify(resp),
headers: { 'Access-Control-Allow-Origin': '*'},
});
}
and it works fine for me. I use to have the same issue as you before, but as long as you define your function with CORS: true and your response contains the header, you should be fine.
Note: Im didnt understand the sintax "map[string]string" and credentials should not be necessary at this case.

It turns out I was ignoring the status code from the response :(
I realized I was actually getting two errors:
A 406 status code for a missing Content-Type header
The CORS error
The first error was caused because I wasn't passing the Content-Type header to the request (I had a check in my code I completely forget that expects that header).
The second error was caused because I didn't add the Access-Control-Allow-Origin header to the error response of my function.

Enable Lamba proxy integration
return events.APIGatewayProxyResponse{
StatusCode: http.StatusOK,
Headers: map[string]string{
"Access-Control-Allow-Origin": "*",
"Content-Type": "application/json",
},
Body: string(jsonEvents),
}, nil

In your terminal, go to the root project path and run:
npm i cors
And, after you need put this code in your index.js:
const cors = require("cors");
app.use(cors());

Related

Api gateway and lambda proxy cors problem

I have a problem with CORS in my API gateway lambda proxy. I was trying to struggle with this but still, I get No 'Access-Control-Allow-Origin' header is present on the requested resource or Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I use apollo client on frontend where I put 'Access-Control-Allow-Origin': '*', header:
const authLink = setContext((operation, { headers }) => {
const token = window.localStorage.getItem('accessToken');
return {
headers: {
...headers,
authorization: `Bearer ${token}`,
'Access-Control-Allow-Origin': '*',
}}}
Next, as a proxy, I use 'apollo-server-lambda' where I have below handler config:
const handler = server.createHandler({
expressGetMiddlewareOptions: {
cors: {
origin: '*',
credentials: true,
},}});
My graphql API gateway invokes some lambdas, every lambda is wrapped in below wrapper:
export const middyfy = (handler: any) => {
return middy(handler).use(middyJsonBodyParser()).use(cors());
};
My graphql proxy serverless configuration looks that:
events: [
{
http: {
method: 'post',
path: '/',
integration: 'lambda-proxy',
cors: true,
},
},
{
http: {
method: 'get',
path: '/',
cors: true,
integration: 'lambda-proxy',
},
},
],
My API gateway OPTIONS configuration:
I will be glad for any help
Problem solved, browser message was confusing.
In the end, I had the error: No 'Access-Control-Allow-Origin' header is present on the requested resource. It was tricky because It wasn't any problem with CORS. I was passing wrong a Cognito JWT Token in my authorization header. Finally, I didn't need to pass 'Access-Control-Allow-Origin': '*', on the frontend side and use cors middleware on the lambda side.

Access to fetch at '' from origin '' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource

I have this api (method get) that is connected to a lambda function that does a simple select from a database, if i test the endpoint with postman with a null body it does work (if i understood, postman is not under the same CORS policy), as well as typing the endpoint on the browser.
But when i try to do a fetch from a simple js, i get the error :
Access to fetch at '...' from origin 'http://localhost' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I enabled CORS in API Gateway, both with the Enable CORS option
and with the Enable API Gateway CORS when creating a new resource
If i test my endpoint with gateway, i also get that Allow-content-allow-origin : * is in my response header :
What should i do to fix this problem?
here is the JS fetch :
console.log("pre fetch");
Show();
console.log("post fetch");
function Show(){
fetch("...").then(onResponse);//.then(onJson);
}
function onResponse(response){
console.log(response);
return response.json();
}
I removed the onJson to avoid confusion, but even with that in its the same problem.
Try to include that in your function too, like this,
I hope this would work:
const headers = {'Content-Type':'application/json',
'Access-Control-Allow-Origin':'*',
'Access-Control-Allow-Methods':'POST,PATCH,OPTIONS'}
const response = {
statusCode: 200,
headers:headers,
body: JSON.stringify(X),
};
return response;
Here X is the response that you want to return.
If you are using Node.js you needs to install cors.
npm install cors.
After installing cors, include it in the page where you are using fetch function as shown below;
const cors = require('cors');
app.use(cors());
and the error will be solved.
I made a video on how to fix this.
You need to go into the Lambda function and add special code:
original (does NOT work):
exports.handler = async (event) => {
// TODO implement
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
return response;
};
new one, that works:
exports.handler = async (event) => {
// TODO implement
const response = {
statusCode: 200,
headers: {
"Access-Control-Allow-Headers" : "Content-Type",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "OPTIONS,POST,GET"
},
body: JSON.stringify('Hello from Lambda!'),
};
return response;
};
You can find this solution in here: https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors.html
Only you need to replace the:
"Access-Control-Allow-Origin": "https://www.example.com",
with
"Access-Control-Allow-Origin": "*",
Special thanks to user, KnowledgeGainer
ALSO, you need to enable CORS on Gateway API side, just follow instruction from here: https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors-console.html

malformed lambda proxy response, can't find the error

I'm trying to get data from my api using lambda and API Gateway, when sending the get requests I get this error:
Execution failed due to configuration error: Malformed Lambda proxy response
the code returns:
return {
'statusCode': 200,
'headers': {'Content-Type': 'application/json'},
'Access-Control-Allow-Origin': '*' ,
"isBase64Encoded": False,
'body': json.dumps(data)
}
what am I doing wrong?
The proxy response must be a dictionary which must only contain the following keys:
headers
body
isBase64Encoded
multiValueHeaders
statusCode
In your example you have one additional key Access-Control-Allow-Origin and that's why API Gateway claims that it is a malformed response. The documentation linked above even explicitly states that Access-Control-Allow-Origin must be part of headers:
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.
If you change the response to the following it should work fine:
return {
'statusCode': 200,
'headers': {
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json'
},
'isBase64Encoded': False,
'body': json.dumps(data)
}

serverless framework AWS REST API Gateway - 403 CORS error

I'm trying to create a function with CORS enabled.
The function works as expected using Postman (cors headers present), but I get CORS error when trying from a browser (no cors header).
const getTicket = async event => {
var ticketNumber = Date.now();
return {
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Methods': '*',
'Access-Control-Allow-Origin': '*',
},
statusCode: 200,
body: JSON.stringify({"ticketNumber": ticketNumber})
};
};
functions:
getTicket:
handler: code/common/ticket.getTicket
runtime: nodejs12.x
events:
- http:
method: get
path: getTicket
cors: true
authorizer:
arn: ${self:custom.auth0.authorizer_arn}
I also tried few more ways of writing the serverless.yaml file, but none of them worked, the only difference between them being the created methods in my API Gateway. Sometimes I got GET+OPTIONS methods, sometimes only GET, but never worked with CORS.
I get the error:
"Access to XMLHttpRequest at 'https://...amazonaws.com/prod/getTicket' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource."
What you are likely seeing is that the server is returning an error before it reaches your return statements. In other words, API Gateway is returning a 502 or 403 (as these are the most common errors), and those specific returns have no CORS headers present by default in API Gateway. I would recommend using CloudWatch to inspect the specific Lambda invocations to determine if your Lambda function itself is erroring out and correct that.
You can also force your API Gateway to return the CORS headers for all responses. In the resources section of the serverless.yml file you can do the following and add any additional entries for other status codes:
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'

CORS issues with Serverless Lambda and API Gateway

Solved
The below issue was simply caused by the body property of the response object constructed in my Lambda. I was forgetting to stringify the data, returning body: data instead of body: JSON.stringify(data). This problem with the response appeared to trigger an error with API Gateway which caused the request failures with some rather confusing error messages.
Problem
I'm working on a ecommerce site using React, Serverless and the Stripe API. My front-end React app is making a GET request using Axios to my Lambda function which has been exposed via API Gateway. The Lambda function in turn queries the Stripe API and returns the Stripe response data to my React app. However, I am experiencing CORS issues as my React app tries to call the Lambda, it receives the following error:
Failed to load: 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 502.
Querying the Lambda endpoint in Insomnia returns a 502 response with { "message": "internal server error" }. But executing the serverless invoke command from the Lambda function from the terminal successfully returns the Stripe data.
I am enabling cors for the function in my serverless.yml file and including 'Access-Control-Allow-Origin': '*' in my Lambda code response as advised in this Serverless blog post, I have also attempted adding a various combinations of the following headers to my Lambda response and my Axios request based on suggestions found on this issue on Axios and this issue on Serverless. I've deleted and redeployed the service multiple times and
Lambda response headers
headers: {
'Access-Control-Expose-Headers': 'Access-Control-Allow-Origin',
'Access-Control-Allow-Credentials': true,
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
React/Axios config
{
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
crossDomain: true
}
Currently my code is as follows:
React app
import Axios from 'axios';
import { GET_PRODUCTS_URL } from '../config';
export default () => {
return Axios
.get(GET_PRODUCT_URL, {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
crossDomain: true
})
.then(({ data }) => data)
.catch(console.log);
}
Lambda
import Stripe from 'stripe';
const apiKey = process.env.STRIPE_SECRET_KEY;
const stripe = Stripe(apiKey);
module.exports.handler = (event, context, callback) => {
return stripe.products
.list()
.then(({ data }) => {
const response = {
statusCode: 200,
headers: {
'Access-Control-Expose-Headers': 'Access-Control-Allow-Origin',
'Access-Control-Allow-Credentials': true,
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
body: data,
};
callback(null, response);
})
.catch(console.log);
}
Serverless.yml
service: srd
provider:
name: aws
runtime: nodejs6.10
stage: ${opt:stage, self:custom.defaultStage}
region: eu-west-1
memorySize: 256
timeout: 6
versionFunctions: true
plugins:
- serverless-plugin-optimize
- serverless-plugin-scripts
package:
individually: true
functions:
get-products:
handler: lambda/get-products.handler
name: srd-get-products-${self:provider.stage}
description: 'get srd products from stripe'
environment:
STRIPE_PUBLISHABLE_KEY: ${self:custom.stripe_publishable_key.${self:provider.stage}}
STRIPE_SECRET_KEY: ${self:custom.stripe_secret_key.${self:provider.stage}}
events:
- http:
path: products
method: get
cors: true
custom:
defaultStage: dev
stripe_publishable_key:
dev: ${file(env.yml):STRIPE_DEV_PUBLISHABLE_KEY}
live: ${file(env.yml):STRIPE_LIVE_PUBLISHABLE_KEY}
stripe_secret_key:
dev: ${file(env.yml):STRIPE_DEV_SECRET_KEY}
live: ${file(env.yml):STRIPE_LIVE_SECRET_KEY}
I've been at this for hours, any insights much appreciated.
Edit/Additional
Making an options request from the CLI returns the following:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 0
Connection: keep-alive
Date: Mon, 19 Mar 2018 06:52:12 GMT
x-amzn-RequestId: 0d10c9d1-2b42-11e8-b270-a723e367048e
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,X-Amz-User-Agent
Access-Control-Allow-Methods: OPTIONS,GET
Access-Control-Allow-Credentials: false
X-Cache: Miss from cloudfront
Via: 1.1 e40b14deb4a844594f746b751f632677.cloudfront.net (CloudFront)
X-Amz-Cf-Id: eMvu3Ke7m7GNFCFgIOGVJmoObFwYMeEt4o8AByoipfMn1nXIi9Vo0g==
The HTTP response code in the CORS error message says 502. This means the server you are requesting is unavailable.
In an event of a 502, the browser cannot make successful OPTIONS requests, so even if your CORS setup in the server is correct, you will still get a CORS error since it was not resolved properly.
Look at your server and make sure it is running as it should. Once the 502 error is fixed, try again and you should be good to go. Try making a manual OPTIONS request, similar to that of what the browser would make, and see if you get the same error.

Resources