API Gateway + Lambda - CORS Issue - aws-lambda

i am experiencing continuing problems with the CORS integration for API Gateway + Lambda. i have enabled CORs for the resources associated with the API. Everything appears to work fine via Lambda testing, Postman testing etc, but calling the api from a webpage script is giving the following error "No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. The response had HTTP status code 415." Do I need to change the Lambda function? Thanks
Here is my simple Lambda code..
'use strict';
var AWS = require('aws-sdk');
var dclient = new AWS.DynamoDB.DocumentClient();
var getItems = (event, context, callback) => {
var params = {
TableName: "OMSCaseDataTest",
Key: {
"IncidentID": event.IncidentID
}
}
dclient.get(params, (error, data) => {
if (error) {
callback(null, "error occured")
} else {
callback(null, data);
}
});
};
exports.getItems = getItems;

If you are using proxy integration in API Gateway, then enabling CORS from API Gateway doesn't work. You have to set the Header 'Access-Control-Allow-Origin' from your Lambda code itself.
Its mentioned in the doc.
Python code sample:
response = {
'statusCode': 200,
'headers': {
'Access-Control-Allow-Origin': '*'
},
'body': json.dumps({'message': 'CORS enabled')
}
return response

Assuming you're using proxy integration, you'll need to handle the CORS yourself. Your lambda function will need to handle the HTTP methods differently. CORS problems usually occur when the pre-flight option request is not entertained. Here's a code snippet could help your cause.
function main(event, context, lambdaCallback) {
if (event.httpMethod === 'OPTIONS') {
doneOptions(200, '{"status": "OK"}', 'application/json', lambdaCallback);
} else if (event.httpMethod === 'POST') {
// do your POST here
} else {
return done(400, '{"message":"Invalid HTTP Method"}', 'application/json', lambdaCallback);
}
}
The functions that return the HTTP 200 to your frontend which decide what your frontend/API could call and what's not.
function doneOptions(statusCode, body, contentType, lambdaCallback, isBase64Encoded = false) {
lambdaCallback(null, {
statusCode: statusCode,
isBase64Encoded: isBase64Encoded,
body: body,
headers: {
'Content-Type': contentType,
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Authorization,Content-Type',
'Access-Control-Allow-Method': 'GET,POST,OPTIONS',
}
});
}

Some times the lambda time out causes CORS error. You can increase the timeout this may fix the issue.

Related

How to return a 401 error with Adonis' websocket middleware

I’m building a websocket middleware and I want to return a 401 from it.
This is my code:
async wsHandle({ request, response }, next) {
let token =request.only('token').token;
await axios.get('auth server url', {
headers: {
'Accept': 'application/json',
'Authorization': token,
},
})
.then(async (response) => {
await next();
})
.catch(err => {
if (err.response) {
let err_code = err.response.status.toString()
//This response can't return responses.
response.status(err_code).send(err.response.data.message)
}
});
}
Can anyone help me please?
Thanks.
Question solved by Harminder Virk : https://forum.adonisjs.com/t/use-websocket-middleware-return-response-401/4473
Answer :
You cannot make standard response with HTTP status codes in websocket connections.
Simply throw an exception from the middleware and AdonisJs will send that error to the channel on('error') event listener on the client.

I can't use json to make a Post request to my web api using react

I created a webapi in ASP.NET Core, and I need to consume it using React, the web api works normally, if I use curl or postman among others, it works normally. The problem starts when I'm going to use React, when I try to make any requests for my API with js from the problem.
To complicate matters further, when I make the request for other APIs it works normally, this led me to believe that the problem was in my API, but as I said it works with others only with the react that it does not. I've tried it in many ways.
The API is running on an IIS on my local network
Attempted Ways
Using Ajax
$ .ajax ({
method: "POST",
url: 'http://192.168.0.19:5200/api/token',
beforeSend: function (xhr) {
xhr.setRequestHeader ("Content-type", "application / json");
},
date: {
name: 'name',
password: 'password'
},
success: function (message) {
console.log (message);
},
error: function (error) {
/ * if (error.responseJSON.modelState)
showValidationMessages (error.responseJSON.modelState); * /
console.log (error);
}
});
Using Fetch
const headers = new Headers ();
headers.append ('Content-Type', 'application / json');
const options = {
method: 'POST',
headers,
body: JSON.stringify (login),
mode: 'cors' // I tried with cors and no-cors
}
const request = new Request ('http://192.168.0.19:5200/api/token', options);
const response = await fetch (request);
const status = await response.status;
console.log (response); * /
// POST adds a random id to the object sent
fetch ('http://192.168.0.19:5200/api/token', {
method: 'POST',
body: JSON.stringify ({
name: 'name',
password: 'password'
}),
headers: {
"Content-type": "application / json; charset = UTF-8"
},
credentials: 'same-origin'
})
.then (response => response.json ())
.then (json => console.log (json))
Using Request
var request = new XMLHttpRequest ();
request.open ('POST', 'http://192.168.0.19:5200/api/token', true);
request.setRequestHeader ('Content-Type', 'application / json; charset = UTF-8');
request.send (login);
ERRORS
Console
Network tab
When I do this without being change the content type to JSON it works
because the API returns saying that it is not a valid type.
Apart from allowing CORS in you .NET configuration. You also need to return 200 OK for all OPTION requests.
Not sure how it's done in .NET but just create a middleware that detects the METHOD of the request, and if it's OPTIONS, the finish the request right there with 200 status.
Well I had the same issue and it seems that you need to add the action to the HttpPost attribute in the controller.
Here is an example.
[HttpPost("[action]")]
public void SubmitTransaction([FromBody] SubmitTransactionIn request)
{
Ok();
}
Try like this
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCors(option => option.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod().AllowCredentials());
app.UseAuthentication();
app.UseMvc();
}

CORS Issue with AWS Lambda and Ajax

So I have been working on this serverless configuration that calls a Lambda function through ajax. The I enable CORs through the API Gateway, and I have made sure of the domain I specified. This domain works when calling other lambda functions within the same API.
Now for the weird stuff.
I send a post request (I am trying to upload a file through ajax, lambda, and S3), to my API. If I configure the Access-Control-Allow-Origin so that it points to the domain WITHOUT the http in front of it. Ex: example.com. When I try to call this i get:
Failed to load https://m562ogkc1l.execute-api.us-east-1.amazonaws.com/test/upload: Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header has a value 'example.com' that is not equal to the supplied origin. Origin 'http://example.com' is therefore not allowed access.
Ok fine, this is assumed, since that's not the proper domain. So when I add in the http (http://example.com) for the CORs of the API I get:
Failed to load https://m562ogkc1l.execute-api.us-east-1.amazonaws.com/test/upload: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://example.com' is therefore not allowed access. The response had HTTP status code 400.
What this seems like to me is that there is an issue elsewhere, except I don't know where the issue lies.
I have made sure the data I pass for parameters of the ajax call are strignified (JSON.stringify()), and I am NOT running an AWS Lambda Proxy which means I shouldn't be configuring responses on the lambda side of things.
This all really confuses me and I wish AWS had better documentation and examples since they really want to push these serverless services.
Further code is here:
Ajax:
$('#submitButton').on('click', function(){
//console.log(document.getElementById('fileUpload').value.substring(12));//C:\fakepath\ in front of filename (size = 12)
$.ajax({
type: 'POST',
url: 'https://m562ogkc1l.execute-api.us-east-1.amazonaws.com/test/upload',
data: JSON.stringify({"id": id,"name": document.getElementById('fileUpload').value.substring(12),"body": document.getElementById('fileUpload').files[0]}),
contentType: "application/json",
success: function(data){
console.log(data);
//location.reload();
}
});
return false;
});
Lambda:
const AWS = require('aws-sdk');
var s3 = new AWS.S3();
exports.handler = async (event) => {
let encodedImage = JSON.parse(event.body);
let decodedImage = Buffer.from(encodedImage, 'base64');
var filePath = event.id + '/' + event.name
var params = {
"Body": decodedImage,
"Bucket": "repository.example.com",
"Key": filePath
};
return await new Promise((resolve, reject) => {
s3.upload(params, function(err, data){
if(err) {
let response = {
"statusCode": 200,
"headers": {
"Access-Control-Allow-Origin": "http://example.com"
},
"body": JSON.stringify(err),
"isBase64Encoded": false
};
resolve(response);
} else {
let response = {
"statusCode": 200,
"headers": {
"Access-Control-Allow-Origin": "http://example.com"
},
"body": JSON.stringify(data),
"isBase64Encoded": false
};
resolve(response);
}
});
});
};
(Yes I threw in some response configuration for the function, I just wanted to see if it would work)

How do I make a CORS request with fetch on my localhost?

I'm building a React/Redux app that integrates with GitHub's API. This app will require users to sign-in using GitHub's OAuth. I'm trying to use the npm package isomorphic-fetch to do the request but cannot seem to get it to work.
Here is the Request:
require('isomorphic-fetch');
var types = require(__dirname + '/../constants/action_types');
module.exports.handleAuthClick = function() {
return function(dispatch, getState) {
var state = getState();
return fetch('http://localhost:3000/auth')
.then(function(res) {
if (res.status <= 200 && res.status > 300) {
// set cookie
// return username and token
return {
type: HANDLE_AUTH_CLICK,
data: res.json()
};
}
throw 'request failed';
})
.then(function(jsonRes) {
dispatch(receiveAssignments(jsonRes));
})
.catch(function(err) {
console.log('unable to fetch assignments');
});
};
};
Here is my Router
authRouter.get('/', function(req, res) {
res.redirect('https://github.com/login/oauth/authorize/?client_id=' + clientId);
});
And here is the Error I keep getting
Fetch API cannot load https://github.com/login/oauth/authorize/?client_id=?myclientID
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://localhost:3000' is therefore not allowed access. If an opaque
response serves your needs, set the request's mode to 'no-cors' to fetch the
resource with CORS disabled.
Looks like this is a security option which prevents a web page from making AJAX requests to different domain. I faced the same problem, and below steps fixed it.
Firstly enable CORS in the WebService app using 'package Manager' console
PM>Install-Package Microsoft.AspNet.WebApi.Cors
Inside App_Start/WebApiConfig.cs file inside the method Register (HttpConfiguration config) add code
config.EnableCors();
Finally add the [EnableCors] attribute to the class
namespace <MyProject.Controllers>
{
[EnableCors(origins: "http://example.com", headers: "*", methods: "*")]
public class MyController : ApiController
{
//some code

How can I send an AJAX request to a node.js server via HTTPS?

I have the following node.js server set up listening to port 9001
var https = require('https');
var fs = require('fs');
var qs = require('querystring');
var options = {
key: fs.readFileSync('privatekey.pem'),
cert: fs.readFileSync('certificate.pem')
};
https.createServer(options, function (req, res) {
res.writeHead(200);
console.log('Request Received!');
console.log(req.method);
if (true || req.method == 'POST') {
var body = '';
req.on('data', function (data) {
body += data;
});
req.on('end', function () {
console.log(body);
var POST = qs.parse(body);
console.log(POST);
});
}
res.end("hello, world\n");
}).listen(9001);
and I am trying to get this server to respond to an AJAX call
function form_save()
{
console.log("submitted!");
var data_obj = {
data1: "item1",
data2: "item2"
}
$.ajax({
url: 'https://adam.testserver.com:9001/',
type: "POST",
dataType: "json",
data: data_obj,
success: function() {
console.log("success!");
},
complete: function() {
console.log("complete!");
}
});
}
There are two problems occurring with my arrangement. The first is that if I start the server and then click the button that triggers my form_save() the node server does not respond and I get the following error:
submitted!
OPTIONS https://adam.testserver.com:9001/ Resource failed to load
jQuery.extend.ajaxjquery.js:3633
$.ajaxjquery.validate.js:1087
form_savew_worksheet.php:64
confirm_deletew_worksheet.php:95
jQuery.event.handlejquery.js:2693
jQuery.event.add.handlejquery.js:2468
w_worksheet.php:73
complete!
At this point if I access that url directy (https://adam.testserver.com:9001/) I get the expected "hello, world" output as well as the console message "Request Received!
GET". From this point on if I click the button to trigger my AJAX call I get a new error.
submitted!
XMLHttpRequest cannot load https://adam.testserver.com:9001/. Origin
https://adam.testserver.com is not allowed by Access-Control-Allow-Origin.
w_worksheet.php:73
complete!
I don't understand why I get this message as both my form and node server reside on the same server. Thanks for taking the time to read, I appreciate any help I can get on this. I've been stuck for a while now!
You've run into the Cross-Origin Resource Sharing (CORS) specification.
Note the OPTIONS in your output. The OPTIONS HTTP Verb is used by the browser to query the web server about the URL, not to GET its contents or POST data to it.
Your server doesn't respond with the correct header data on a CORS request, so your browser assumes it has no rights to access the data, and refuses to GET or POST to the URL.
If you truly want to let any website in the world run that AJAX request, you can do something similar to the following:
function handleOptions(request, response) {
response.writeHead(200, {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Method": "POST, GET, OPTIONS",
"Access-Control-Allow-Headers": request.headers["access-control-request-headers"]
});
response.end();
}
function server(request, response) {
if(request.method == "POST") {
handlePost(request, response);
} else if(request.method == "OPTIONS") {
handleOptions(request, response);
} else {
handleOther(response);
}
}
https.createServer(sslObj, server).listen(9001);
You can fill in the details and whether you should handle GET separately, and so on (handleOther should return an appropriate error code for each request method you don't support).

Resources