ReactJS aws blocked by CORS preflight policy - reactjs

I've been trying to make a simple post request api so that my reactJS frontend can make posts, and have them populate in a table in DynamoDB. I've created the a dynamoDB table, given a lambda function permission to make requests to this table, and an API gateway to use a url to make the rest api requests. I originally did not have the intergration request in API gateway set to lambda proxy, but from the advice of aws support, I've enabled it.
This is the code I'm using in my lambda function (with the api gateway (REST API) as the trigger):
const AWS = require('aws-sdk');
const docClient = new AWS.DynamoDB.DocumentClient({region: "us-east-1"});
exports.handler = (event, context, callback) => {
console.log("Processing...");
const {name} = JSON.parse(event.body);
const params = {
TableName: "serverlessAppTest",
Item: {
date: Date.now(),
name: name,
},
};
let responseBody = {
name: name,
}
const response = {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true,
"Access-Control-Allow-Headers" : "Content-Type",
"Access-Control-Allow-Methods": "OPTIONS,POST,GET"
},
body: JSON.stringify(responseBody)
};
docClient.put(params, function(err, data) {
if(err){
callback(err, null);
} else {
callback(null, data);
}
})
console.log("response: " +JSON.stringify(response))
return response;
};
When I try to reach the post api with the following body in the test area in lambda:
{
"body": "{\"name\": \"Value from Lambda\"}"
}
I got a 200 OK, and the data is populated in the dynamoDB table. It also works correctly in postman, a 200 OK and data uploaded.
When I try in my reactjs code, I get the following response:
Access to XMLHttpRequest at 'https://{apivalhere}.execute-api.us-east-1.amazonaws.com/default/serverlessAPICalls' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Here's my reactjs function to make the call with a button push.
import React from "react";
import axios from "axios";
function FormHook() {
const apiURL =
"https://{apivalhere}.execute-api.us-east-1.amazonaws.com/default/serverlessAPICalls";
const submitHandler = (e) => {
e.preventDefault();
console.log("did it");
const headerData = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Credentials": true,
"Access-Control-Allow-Headers":
"Origin, Content-Type, X-Auth-Token",
"Access-Control-Allow-Methods":
"GET, POST, PATCH, PUT, DELETE, OPTIONS",
};
axios
.post(
apiURL,
{
name: "Hello from reactjs!",
message: "this is the message field.",
},
{
headers: headerData,
}
)
.then((res) => {
console.log(res);
console.log(res.data);
})
.catch((err) => {
console.log(err);
});
};
return (
<div>
<form onSubmit={submitHandler}>
<button type="submit">Send</button>
</form>
</div>
);
}
export default FormHook;
I've gone through about a dozen or more docs on stackoverflow and aws support trying to resolve this issue, and I keep getting blocked with this cors issue. I've tried specifically stating "application/json" in my headers, along with specifically allowing 'localhost:3000', then tried '*' in the Control Allow Origin for both the lambda node.js code, and reactjs post method. I'm at a complete loss at what I could do to fix this and could use some help. I'm relatively new with making my own functions to handle api requests, so any guidance or suggestions would be much appreciated.
edit:
I received the same CORS error with the following as well.
import React from "react";
import axios from "axios";
function FormHook() {
const apiURL =
"https://{apivalhere}.execute-api.us-east-1.amazonaws.com/default/serverlessAPICalls";
const submitHandler = (e) => {
e.preventDefault();
console.log("did it");
axios
.post(
apiURL,
{
name: "Hello from reactjs!",
message: "this is the message field.",
},
)
.then((res) => {
console.log(res);
console.log(res.data);
})
.catch((err) => {
console.log(err);
});
};
return (
<div>
<form onSubmit={submitHandler}>
<button type="submit">Send</button>
</form>
</div>
);
}
export default FormHook;

For my setup in particular, the issue was in my api gateway configuration and process in lambda. I was not handling the OPTIONS request, which was causing the bad gateway (502 error). To fix this, in the api gateway I'd set an OPTIONS methods integration request type to MOCK. This causes the api gateway to just chuck out whatever OPTIONS request it gets, and allows the following post request to come through.
This is definitely not best practice and will be updated to handle the OPTIONS request more gracefully, but it's working now.

This great article explains the solution: AWS CORS Policy with React
You have to go through to every detail, I also read it several times to realise how to set the headers for every request right.

Related

how to allow CORS on my api rest when I fetch her with react?

I try to call my symfony api rest with react but I can't.
I can call my api on postman or online (https://bilemo.thomas-dasilva.fr/BileMo/doc) you can try with username: mail#gmail.com and password: Test1234? it work good but not with fetch.
I try many post on stackoverflow but I didn't because it's my api and I try to change cors
I have this error:
Access to XMLHttpRequest at 'https://bilemo.thomas-dasilva.fr/BileMo/login_check' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
I try to add on my api an EventSubscriber
<?php
namespace App\EventSubscriber;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class ResponseSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
// return the subscribed events, their methods and priorities
return [
KernelEvents::RESPONSE => 'onKernelResponse'
];
}
public function onKernelResponse (ResponseEvent $event)
{
$responseHeaders = $event->getResponse()->headers;
$responseHeaders->set('Access-Control-Allow-Headers', 'origin, content-type, accept, credentials');
$responseHeaders->set('Access-Control-Allow-Origin', 'http://localhost:3000');
$responseHeaders->set('Access-Control-Allow-Credentials', 'true');
$responseHeaders->set('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, PATCH, OPTIONS');
}
}
and on my react I just try this :
import React, { useEffect } from "react";
import Navigation from "../conponents/Navigation";
import axios from "axios";
const App: React.FC = () => {
useEffect(() => {
axios({
url: "https://bilemo.thomas-dasilva.fr/BileMo/login_check",
method: "post",
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
},
data: {
username: "mail#gmail.com",
password: "Test1234?",
},
}).then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
//let responseJson = await response.json();
});
return (
<div>
<Navigation />
</div>
);
};
export default App;

CORS error while trying to post data with Axios on AWS REST API configuration using a node.js Lambda function

I'm posting data to a DynamoDB table with axios in a React front-end.
The API is set up through a serverless configuration with an API Gateway and Lambda on AWS.
While the request goes through and I see the added item on the database I still get a CORS error https://i.stack.imgur.com/m7yMG.jpg
This is the axios method:
import axios from "axios";
export const sendItemToDB = async (_data) => {
if (!_data) { return };
try {
const res = await axios({
method: "POST",
url: process.env.REACT_APP_QUERY_API,
data: _data,
headers: {
"Content-Type": "text/plain"
},
});
console.log("data returned from api", res);
} catch (error) {
console.log("Error sending File to db: ");
console.log(error);
}
};
And the API method on Lambda:
const createRecord = async (event) => {
const response = { statusCode: 200 };
try {
const body = JSON.parse(event.body);
const params = {
TableName: process.env.DYNAMODB_TABLE_NAME,
Item: marshall(body || {}),
};
const createResult = await db.send(new PutItemCommand(params));
response.body = JSON.stringify({
message: "Successfully created record.",
createResult,
});
} catch (e) {
console.error(e);
response.statusCode = 500;
response.body = JSON.stringify({
message: "Failed to create record.",
errorMsg: e.message,
errorStack: e.stack,
});
}
return response;
};
I based this configuration on this tutorial : https://github.com/jacksonyuan-yt/dynamodb-crud-api-gateway
I solved this following amazon documentation and reconfiguring the serveless deployment yml.
Serverless documentation on api gateway and lambda proxy integration here
Adding the missing headers to all lambda functions was essential.
const response = {
statusCode: 200,
headers: {
"Access-Control-Allow-Headers" : "Content-Type",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "OPTIONS,POST,GET"
},
};
Also testing that OPTIONS is working for the preflight:
https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-test-cors.html
Just as Stavros noticed, the problem is that this is not a simple cross-origin POST method request (because it contains custom headers), so you need to tweak CORS settings of AWS API Gateway by adding
"POST, GET & OPTIONS" for Access-Control-Allow-Methods
"content-type" for Access-Control-Allow-Headers
You can do it through console like this
You also might need to add those headers in lambda like this
and it will work.

Get the set-cookie header from response but it doesn't store in the browser

I am currently working on a project using Ionic React with .NET API for login process.
And this is the problem I am facing:
This is the Response Header of my post request
And when I try to look at the application cookie, it seems that it is not being set.
This is the application view which should see the jwt cookie has been stored.
I have already added these two params for my Axios post request but not work at all.
{withCredentials: true, credentials: 'include'}
Thank you for your time to look into my question or help!!!
Below are my request/response setting on the client-side and backend:
Axios request:
const api = axios.create({
baseURL: `https://localhost:7220/api/User`
})
api.post("/login", postData, {withCredentials: true, credentials: 'include'})
.then(res => {
console.log(res);
})
.catch(error=>{
console.log(error);
})
Controller:
Response.Cookies.Append(key: "jwt", value: token, new CookieOptions
{
HttpOnly = true
});
Response response = new Response { Status = true, Message = _LOGINSUCCESSFUL };
return Ok(response);
Program.cs:
builder.Services.AddCors(p => p.AddPolicy("corsapp", builder =>
{
builder.WithOrigins("http://localhost:3000").AllowCredentials().AllowAnyMethod().AllowAnyHeader().AllowAnyMethod();
}
)
);

Implementing google-recaptcha v3 in react without a backend

I'm a frontend developer trying to create a test case of adding google-recaptcha-v3 in my react app.
I'd appreciate response to how i can by-pass the cors error when I make a post request to verify the user's token.
//imports
...
const Recaptcha=()=>{
return(
<div>
<p>Recaptcha Test</p>
<button onClick={handleSubmit}>Send Test</button>
</div>
)
// handleSubmit function
const handleSubmit =()=>{
const getToken = async () => {
await executeRecaptcha('contactpage')
.then(res=>{
console.log(res);
return setToken(res);
});
}
getToken();
console.log(token);
const verifyToken = async () => {
console.log(token);
const article = {
secret: '*******',
response: token
}
let axiosConfig = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
"Access-Control-Allow-Origin": "http://localhost:3000",
}
};
let url = 'https://www.google.com/recaptcha/api/siteverify';
await axios.post(url, article)
.then(res => console.log(res))
.catch(err => console.log(err));
}
verifyToken();
}
Then I get this error in my browser console:
Access to XMLHttpRequest at 'https://www.google.com/recaptcha/api/siteverify' from origin 'http://localhost:3000/' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Google is not allowing you to call 'https://www.google.com/recaptcha/api/siteverify' from a frontend because of their CORS policy. See Mozilla's CORS guide for more information about CORS. Calls can only be initiated from a backend and not from a browser.

Getting 400 error Bad request using axios

I am using axios and getting a 400 bad request error. I am using react-redux and trying to send a post request to localhost:3000/posts. Here is the code that I am using.
import axios from 'axios';
import {
GET_ALL_POSTS,
GET_POST,
CREATE_POST,
DELETE_POST,
UPDATE_POST
} from './types';
const ROOT_URL = 'http://localhost:3000';
export function createPost({content, title}, cb) {
return function(dispatch) {
axios.post(`${ROOT_URL}/posts`, {content, title})
.then((response) => {
console.log(response);
dispatch({
type: CREATE_POST,
payload: response
});
})
.then(() => cb())
.catch((error) => {
console.log("Problem submitting New Post", error);
});
}
}
i was also getting this error, the issue was not with server or with axios or proxy url.
The issue was i wasn't sending the correct data from my react application.
For Example
i supposed to send:
{ email: 'ib2#gmail.com', password: 'asdf' }
what i was sending is:
{ name: 'ib2#gmail.com', password: 'asdf' }
this caused api don't understand name field, as i provided email as the key in api.
so if you are still facing the issue try to check if you are sending the correct data.
For every post request, the client first sends an OPTIONS request to check whether the server is ready to accept the connection. You should also allow the server to accept options request. If you have not allowed use the below lines in case of node server
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS');
next();
});

Resources