CORS response when sending a DELETE request - javascript

I am trying to send a DELETE request to my backend server, but I keep getting this response printed to my console:
Response {type: 'cors', url: 'http://localhost:3003/delete', redirected: false, status: 200, ok: true, …}
body: (...)
bodyUsed: false
headers: Headers {}
ok: true
redirected: false
status: 200
statusText: "OK"
type: "cors"
url: "http://localhost:3003/delete"
[[Prototype]]: Response
I don't know why this is happening.
server.js
const express = require('express')
const knex = require('knex')
const cors = require('cors')
const db = knex({
client: 'pg',
connection: {
host: '127.0.0.1',
user: 'postgres',
password: 'psql',
database: 'blogspot',
port: 5432
}
});
const app = express();
app.use(express.json())
app.use(cors())
// Delete Blog
app.delete('/delete', (req, res) => {
const {id} = req.body;
db.select('*').from('blogs')
.where({
id: id
})
.del()
.then(() => {
res.json('Deleted Successfully')
})
.catch(err => res.status(404).json('An error occured'))
})
fetchAPI.js
function deleteBlog (blog) {
fetch('http://localhost:3003/delete', {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(blog)
}).then(resp => {
console.log(resp)
if (resp === 'Deleted Successfully') {
navigate(0)
} else if (resp === 'An error occured') {
console.log('Something went wrong')
} else {
console.log('ERROR')
}
})
}
I keep getting 'ERROR' printed to my console along with the cors response I pasted above. When I refresh, I find that the blog has been deleted, but the response was definitely an error since navigate(0) wasn't run and ERROR was printed to my console. I have tried removing the 'Content-Type': 'application/json' header and sending the id as request params instead but I got the same error.

The fact that the response is of type "cors" just means that some contents are filtered by CORS policy (see https://developer.mozilla.org/en-US/docs/Web/API/Response/type) but you didn't get any error code, the statusCode is 200.
Since your response content type is JSON, you must also resolve the json parsing before reading the response:
function deleteBlog(blog) {
fetch('http://localhost:3003/delete', {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(blog)
})
.then(data => data.json())
.then(resp => {
// I also suppose that you will more likely find
// your "Deleted successfully" in the resp.body property, so :
if (resp.body === 'Deleted Successfully') {
navigate(0)
} else if (resp.body === 'An error occured') {
console.log('Something went wrong')
} else {
console.log('ERROR')
}
})
}

Related

Unable to fetch Yelp API when MERN stack

I set up the my express backend to fetch restaurant with the dish name from Yelp API, and receive the request from my frontend, but browser gave me POST http://localhost:5000/api/search/ net::ERR_ABORTED 403 (Forbidden).
Frontend:
item would be the dish name
let backend
if (document.location.hostname === 'localhost') {
backend = 'http://localhost:5000/'
} else {
backend = 'https://meals4yo.herokuapp.com/'
}
useEffect(() => {
fetch(`${backend}api/search/`, {
method: 'post',
mode: 'no-cors',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({term: item})
})
.then(response => response.json())
.catch(err => {
console.log(err)
})
},[])
Backend:
app.post('/api/search', function(req, res) {
debugger
let request = axios.create({
headers: {
Authorization: `Bearer API_KEY`,
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET,PUT,POST,DELETE,PATCH,OPTIONS"
}
})
request
.get('https://api.yelp.com/v3/businesses/search', {
params: {
term: req.body.term,
location: "nyc"
}
})
.then(response => {
console.log(response.data)
res.json(response.data.businesses)
})
.catch (err => {
console.log(err)
})
})
I tried to add mode: "no-cors" and used axios to do the fetch in the frontend, none of those work

HttpOnly cookies are not sent with request to server

I've created API in node express and I'm running it on port :8000, I am consuming APIs through simple CRA on port :3000. I've created registration and login with setting httpOnly cookie. Furthermore, I've put middleware to check each endpoint in order to verify if it has that token.
When I test through Thunder/Postman everything works, after logging in I get the cookie in response, I set that cookie as auth token and make request to get data and I get the data.
When I log in through the React Frontend it succeeds and I can see in network tab that I have received the cookie in response. But when I make a request to protected endpoint, the request does not have a cookie in it (I log incoming requests on server and compare ones made with Thunder/Postman client and via app in Browser).
I use axios, and I've put {withCredentials: true} it doesn't work. I've used withAxios hook and it doesn't work either.
SERVER
index.js
...
const app = express()
app.use(cors({
credentials: true,
origin: 'http://localhost:3000',
}));
...
controllers/User.js
...
const loginUser = async(req, res) => {
const body = req.body
const user = await User.findOne({ email: body.email })
if(user) {
const token = generateToken(user)
const userObject = {
userId: user._id,
userEmail: user.email,
userRole: user.role
}
const validPassword = await bcrypt.compare(body.password, user.password)
if(validPassword) {
res.set('Access-Control-Allow-Origin', req.headers.origin);
res.set('Access-Control-Allow-Credentials', 'true');
res.set(
'Access-Control-Expose-Headers',
'date, etag, access-control-allow-origin, access-control-allow-credentials'
)
res.cookie('auth-token', token, {
httpOnly: true,
sameSite: 'strict'
})
res.status(200).json(userObject)
} else {
res.status(400).json({ error: "Invalid password" })
}
} else {
res.status(401).json({ error: "User doesn't exist" })
}
}
...
middleware.js
...
exports.verify = (req, res, next) => {
const token = req.headers.authorization
if(!token) res.status(403).json({ error: "please provide a token" })
else {
jwt.verify(token.split(" ")[1], tokenSecret, (err, value) => {
if(err) res.status(500).json({error: "failed to authenticate token"})
req.user = value.data
next()
})
}
}
...
router.js
...
router.get('/bills', middleware.verify, getBills)
router.post('/login', loginUser)
...
CLIENT
src/components/LoginComponent.js
...
const loginUser = (e) => {
setLoading(true)
e.preventDefault()
let payload = {email: email, password: password}
axios.post('http://localhost:8000/login', payload).then(res => res.status === 200
? (setLoading(false), navigate('/listbills')) : navigate('/register'))
}
...
src/components/ListBills.js
...
useEffect(() => {
fetch('http://localhost:8000/bills', {
method: 'get',
headers: {'Content-Type': 'application/json'},
credentials: 'include',
})
.then(response => {console.log(response)}).catch(err => console.log(err));
}, [])
...
I've also tried:
axios.get('http://localhost:8000/bills',{withCredentials: true})
.then((data) => console.log(data))
.then((result) => console.log(result))
.catch((err) => console.log('[Control Error ] ', err))
}
and
const [{ data, loading, error }, refetch] = useAxios(
'http://localhost:8000/bills',{
withCredentials: true,
headers: {'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json'
}})
Console.log error:
After I login I get this in Network tab:
However when I want to access the list:
=== UPDATE ===
So the cause of the issue is not having the httpOnly cookie passed in the request header. This is the log of the middleware I am using:
token undefined
req headers auth undefined
req headers {
host: 'localhost:8000',
connection: 'keep-alive',
'sec-ch-ua': '" Not;A Brand";v="99", "Google Chrome";v="97", "Chromium";v="97"',
'sec-ch-ua-mobile': '?0',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36',
'sec-ch-ua-platform': '"macOS"',
'content-type': 'application/json',
accept: '*/*',
origin: 'http://localhost:3000',
'sec-fetch-site': 'same-site',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
referer: 'http://localhost:3000/',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'en-US,en;q=0.9,hr;q=0.8,sr;q=0.7,bs;q=0.6,de;q=0.5,fr;q=0.4,it;q=0.3'
}
token is read from headers.authorization but from the log of the headers it doesn't exist so my requests fail to be authorized.
Still not working.
After reading everything on CORS and httpOnly cookies I've managed to get it working.
First I removed sameSite and added domain prop according to documentation in controllers/User.js on SERVER
res.cookie('auth-token', token, {
httpOnly: true,
domain: 'http://localhost:3000'
})
Then I got a little yellow triangle in the console request view, it said that domain was invalid. Then I just changed domain to origin and the cookie appeared in the request log of the headers 🎉
res.cookie('auth-token', token, {
httpOnly: true,
origin: 'http://localhost:3000',
})
The cookie was not in the Authorization property of the headers but in the cookie so I had to change the code in the middleware.js since it expected format bearer xxyyzz but receiving auth-token=xxyyzz, it looks like this now:
exports.verify = (req, res, next) => {
const token = req.headers.cookie
if(!token) res.status(403).json({ error: "please provide a token" })
else {
jwt.verify(token.split("=")[1], tokenSecret, (err, value) => {
if(err) res.status(500).json({error: "failed to authenticate token"})
req.user = value.data
next()
})
}
}

'Access-Control-Allow-Credentials' header in the response is ' ' which must be 'true' when the request's credentials mode is 'include' [duplicate]

This question already has answers here:
'Access-Control-Allow-Credentials' header in the response is '' which must be 'true'
(2 answers)
Closed 2 years ago.
I am learning server-client communication in the course of making MMORPG project.
*update: server side code is edited.
This is server side code.
router.post('/login', async (request, response, next) => {
passport.authenticate('login', async (error, user) => {
try {
if (error) {
return next(error);
}
if (!user) {
return next(new Error('email and password are required'));
}
request.logIn(user, { session: false }, (err) => {
if (err) {.....
This is client side code
function postData(url, data = {}) {
return fetch(url, {
method: 'POST',
mode: 'cors',
cache: 'no-cache',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
},
redirect: 'follow',
body: JSON.stringify(data),
}).then((response) => response.json());
}
login() {
const loginValue = this.loginInpout.value;
const passwordValue = this.passwordInput.value;
postData('http://localhost:4000/login', { email: loginValue, password: passwordValue })
.then((response) => {
if (response.status === 200) {
this.startScene('Game');
} else {
console.log(response.message);
window.alert('invald username or password');
}
}).catch((error) => {
console.log(error.message);
window.alert('invald username or password');
});
}
when login() function is called, fetch() function throws this message in browser console.
(http://localhost:4000/login) is server side and (http://localhost:8000) is client side.
Access to fetch at 'http://localhost:4000/login' from origin 'http://localhost:8000'
has been blocked by CORS policy: Response to preflight request doesn't pass access
control check: The value of the 'Access-Control-Allow-Credentials' header in the
response is '' which must be 'true' when the request's credentials mode is 'include'.
LoginScene.js:48 POST http://localhost:4000/login net::ERR_FAILED
Failed to fetch <<-- fetch error message on browser console
I tried to fix it many different ways with no good outcome.
Try the following code:
import express from "express";
import http from "http";
const app = express();
const server = http.createServer(app);
const sio = require("socket.io")(server, {
handlePreflightRequest: (req, res) => {
const headers = {
"Access-Control-Allow-Headers": "Content-Type, Authorization",
"Access-Control-Allow-Origin": req.headers.origin,
"Access-Control-Allow-Credentials": true
};
res.writeHead(200, headers);
res.end();
}
});
sio.on("connection", () => {
console.log("Connected!");
});

Can not download file while sending request from one node.js server to another

I am facing some issue while downloading file using node.js. I have scenario like my angular component is sending the file request. in my first node server I am doing the token validation and then redirecting to another node server where actually the execution happens. I am explaining my code below.
service.ts:
submitAndDownloadFile(formdata : any ){
const token = localStorage.getItem('token')
let headers = new HttpHeaders({
Authorization: 'Basic ' + token
})
const cecID = localStorage.getItem('cec');
const AppUrl = `${environment.nodeJsBaseUrl}:${environment.hostingNodeJsContainerPort}/convert-test-cases/${cecID}`;
return this.httpClient.post(AppUrl, formdata, { responseType: 'blob', observe : 'response', headers : headers});
}
Here I am sending the request to my first node.js server which code has given below.
app.js(first:port-8000):
router.post('/convert-test-cases/:id', middleware.auth, (req, res) => {
try{
let postRequestOptions = {
url: '',
method: 'POST',
json: true,
headers: {},
body: {},
};
postRequestOptions.url = 'http:localhost:9000/convert-test-cases';
postRequestOptions.headers = {
'Content-Type': 'application/json',
};
postRequestOptions.body = req.body;
request(postRequestOptions, async (error, response, pathList) => {
if(error) {
console.log('error', error);
}else{
res.send(pathList);
}
})
}catch(e){
responseObj = {
status: 'error',
msg: 'Error occurred while processing your request',
body: null
}
return res.send(responseObj);
}
})
Here I am doing the token validation using middleware.auth and sending same request to another node.js file which code is explained below.
app.js:(second-port-9000):
router.post('/convert-test-cases', async (req, res) => {
try{
let response = await ctcCtrl.convertTestCase(req.body, req.files);
if(response.status == 'success'){
res.set('Access-Control-Expose-Headers','*, Content-Disposition');
return res.download(response.fileName,response.fileName);
}else{
return res.send(response);
}
}catch(e){
responseObj = {
status: 'error',
msg: 'Error occurred while processing your request',
body: null
}
return res.send(responseObj);
}
})
Here only I am doing some execution and downloading the file. If I am connecting angular to node-9000 its working fine but my requirement is first I have to connect to port-8000 to some token validation and after that I have to send same req.body and re.file to app.js which is running in 9000 using request module. As per my code its not working at all.

Node/Express - res.status().send() only sends the status but does not send an object

I am having an issue with a route in my backend where res.status().send() will only send the client the status code, but it will not send the client the object located inside of send().
Here is my code (redacted all code but the problem for brevity):
exports.user_signup = (req, res) => {
const { body } = req;
const { companyName, password, email } = body;
User.find({ email: email }, (err, previousUsers) => {
if (err) {
return res.status(400).send({
message: "There was an issue signing up."
});
} else if (previousUsers.length > 0) {
return res.status(403).send({
message: "Records show this email is linked to another account."
});
}
}
When I make my fetch request from the client, the response only returns the status code from the server, but nowhere in the response is the object in the send() method on the server. Just spitballing, I threw res.status(200).json(object) at it to send the object as json to no avail.
Here is my `fetch request from the client:
fetch("http://localhost:3000/users/accounts/", {
method: "post",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(userData)
}).then(response => console.log(response));
}
To show what response I am getting, I purposely posted some form data from the client to the route that would throw the 403 error, and this is the response I get in the browser console:
Response {type: "basic", url: "http://localhost:3000/users/accounts/", redirected: false, status: 403, ok: false, …}
So I am able to successfully send the status back from the route to the client, however I can not for the life of me figure out why send() does not send the object along with it.
The body of the response that comes back from fetch() is a ReadableStream. You need to process it to turn it into something usable. Normally you would call response.json() to parse it as a JSON object:
fetch("http://localhost:3000/users/accounts/", {
method: "post",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
body: JSON.stringify(userData)
})
.then(response => response.json())
.then(response => console.log(response));
}

Categories

Resources