cors request failed on vue/express - node.js

I'm running a vue app on an apache server on a virtual server. Express is started with nodemon.
When trying to login I'm getting a
Cannot read property 'status' of undefined xhr.js:160
POST https://143.93.46.35:60702/user/login net::ERR_TIMED_OUT
on chrome and
Cross-source (cross-origin) request blocked: The same source rule prohibits reading the external
resource on https://143.93.46.35:60702/user/login. (Reason: CORS request failed)
on firefox.
In vue my axios baseURL looks like (node is running on port 60702):
const apiClient = axios.create({
baseURL: `https://pvapp.umwelt-campus.de:60702`,
withCredentials: false, // This is the default
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
})
export default{
loginUser (user) {
return apiClient.post(`/user/login`, user)
},
...
}
And the user route on express is:
router.post('/login', async (req, res) => {
let compareUser = await db.query('SELECT * FROM app_users WHERE username=? LIMIT 1', [req.body.username]); // use db.query() to retrieve the password
if (compareUser.length < 1) // compareUser is an array with at most one item
res.sendStatus(403);
let valid = bcrypt.compareSync(req.body.password, compareUser[0].password);
if (!valid)
res.sendStatus(403);
let user = new User(compareUser[0]);
const token = jwt.sign({ user }, nconf.get('jwtToken'), { expiresIn: '14d' });
Object.assign(user, { token });
res.json(user);
});
In app.js cors is enabled like:
app.use(cors());

You need to res.setHeader('Access-Control-Allow-Origin', YourOrigin); in a middlewar before app.use(cors()); in order to allow the client.
EDIT :
You can do something like this :
router.use(function (req, res, next) {
let origin = req.headers.origin;
if (allowedOriginsTab.includes(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin);
}
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});

Related

CORS blocking my node server from react app localhost

Tried everything I could find on here in regards to setting up cors for my node server. Tried aliasing my localhost and that doesn't seem to work either. Also tried using the CORS unblock extension.
error: localhost/:1 Access to fetch at
'http://localhost:8080/api/login' 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.
:8080/api/login:1 Failed to load resource: net::ERR_FAILED
im trying to use magic link authentication in my react app. I got this POST request being made to my node server
const res = await fetch(`http://localhost:8080/api/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer ' + didToken,
},
});
my server code is
const express = require("express");
const cors = require("cors");
const { Magic } = require('#magic-sdk/admin');
require('dotenv').config();
const app = express()
const magic = new Magic(process.env.MAGIC_SECRET_KEY);
app.use("*", (req, res) => res.status(404).json({ error: "not found" }));
// Allow requests from client-side
app.use(cors({origin: process.env.CLIENT_URL}));
app.all('*', (req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Credentials', 'true');
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
res.header(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept, Authorization'
);
res.sendStatus(200);
next();
});
app.post('api/login', async (req, res) => {
console.log("login fired")
try {
const didToken = req.headers.authorization.substr(7);
await magic.token.validate(didToken);
res.status(200).json({ authenticated: true });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
module.exports = app
app.use(cors({origin: process.env.CLIENT_URL}));
I'd be curious what this URL is. If you want an open CORS policy you don't need to set anything any there.
Put a "/" in front of this route
app.post('/api/login', async (req, res) => {
I was able to reproduce your problem locally and this server setup worked for me to fix it.
const express = require("express");
const cors = require("cors");
const port = 8080;
const app = express();
app.use(cors());
app.post("/api/login", async (req, res) => {
console.log("login fired");
try {
res.status(200).json({ authenticated: true });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.listen(port, () => {
console.log(`Example app listening on port ${port}`);
});
module.exports = app;

React & Node.js fetch basic authorization

I am using fetch api to make request from reactjs to node.js backend with Basic Authorization with the code below...
React
fetch(baseUrl, {
method: 'get',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
authorization: 'Basic ' + secret,
},
}).then((res) => {
if (res.ok) {
return res.json();
} else {
return Promise.reject(res.statusText);
}
})
.then((resBody) => {
//
})
.catch((error) => {
console.error(error);
});
Node.js
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Authorization');
res.setHeader('Access-Control-Allow-Credentials', true);
return next();
});
app.use((req, res, next) => {
const base64Credentials = (req.headers.authorization || '').split(' ')[1] || '';
const [username, password] = Buffer.from(base64Credentials, 'base64').toString().split(':');
const auth = { username: 'username', password: '123456' }
console.log(username, password, auth.username, auth.password);
// comment below
if (username === auth.username && password === auth.password) {
return next();
} else {
res.status(401).send('Authentication required.'); // custom message
}
});
The following error is occur when I try to make the request.
Access to fetch at 'http://127.0.0.1:5000/' 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.
However, when I comment the comparison part in the second middleware if (username === auth.username && password === auth.password) it works fine. I have tried using Postman to send request it also no problem happen. The problem only occur when I make the request from react app. Anyone know what is the reason? Thanks a lot
it seems that the CORS npm is no installed npm i cors and write this code:
var express = require('express')
var cors = require('cors')
var app = express()
app.use(cors())
more information about CORS npm

storing and retrieving data,achieved through REST to mongodb using fetch on node

methods: {
onclicksubmit: function () {
const user = {
firstname: this.firstname
}
const options = {
method: 'POST',
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify(user)
};
fetch('http://localhost:3000/register', options).then(response => {
console.log('success', response);
}).catch((error) => {
console.error('Error:', error);
});
},
When I click on the submit button it should send the data to the database but there is an error appearing which says 'failed to fetch.'
This is the backend code:
app.use(bodyParser.json())
app.post('/register', function (req, res) {
res.send({
firstname: req.body.firstname,
})
console.info("Request body: " + JSON.stringify(req.body));
db.collection('user').insertOne(req.body, req.body.firstname, function (err, res) {
if (err) return console.log(err)
else res.send('success!')
console.log('saved to mongodb');
})
});
You are trying to make a request to a different domain than your page is on. So the browser is blocking it as it usually allows a request in the same origin for security reasons. When you are using postman they are not restricted by this policy.
You could use code like this to enable CORS.
// Add headers
app.use(function (req, res, next) {
// Website you wish to allow
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8888');
// methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
// headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
next();
});
OR
const express = require('express')
const cors = require('cors')
const app = express()
app.post('/register', cors(), (req, res, next) => {
})

CORS issue with Restify

I have created a ReactJs app with a Node Api which uses Restify, but whatever I do I always have the error for POST method :
405 (Method Not Allowed)
Access to fetch at 'http://localhost:3001/api/login' 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. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I have tried everything I saw on Internet but I always have this issue.
To call the API, here is my code :
const request = new Request(url + 'login', {
method: 'POST',
body: JSON.stringify({ 'username' : username, 'password' : password }),
headers: new Headers({ 'Content-Type': 'application/json' })
})
return fetch(request)
.then(response => {
if (response.status < 200 || response.status >= 300) {
throw new Error(response.statusText);
}
return response.json();
})
.then(({ token }) => {
localStorage.setItem('token', token);
});
And I configure Restify like this :
const config = require('./config'),
restify = require('restify'),
errs = require('restify-errors');
var connection = config.db.get
const server = restify.createServer({
name: config.name,
version: config.version,
url: config.hostname
});
server.use(restify.plugins.acceptParser(server.acceptable));
server.use(restify.plugins.queryParser());
server.use(restify.plugins.bodyParser());
server.use(
function crossOrigin(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, OPTIONS, DELETE');
res.header('Access-Control-Allow-Credentials', false);
return next();
}
);
server.listen(3001, function () {
console.log('%s listening at %s', server.name, server.url);
});
server.post("/api/login", function (req, res) {
res.send(200);
});
So I expect to receive a validation (code 200) after calling the Api, but I always have CORS issue.
Is there anything else to configure ?
Thanks for your help !!! :D
You have to use corsMiddleware to avoid cors issue....write this code in your app.js file ...it should be work fine
var restify = require('restify');
var corsMiddleware = require('restify-cors-middleware');
var cors = corsMiddleware({
preflightMaxAge: 5,
origins: ['*'],
allowHeaders:['X-App-Version'],
exposeHeaders:[]
});
/**
* Initialize Server
*/
var server = restify.createServer();
server.pre(cors.preflight);
server.use(cors.actual);

How to set cookies express, react.js

I am building a login system using express for node.js and react.js. In my back-end when a user logs in, it creates a cookie. When I go to Network > Login I can see this:
Set-Cookie:
user_id=s%3A1.E%2FWVGXrIgyXaM4crLOoxO%2Fur0tdjeN6ldABcYOgpOPk; Path=/; HttpOnly; Secure
But when I go to Application > Cookies > http://localhost:3000, there is nothing there. I believe that is because I am not allowing credentials to go through correctly when I do a post request from the client side. How do I go about this? Please, let me know if I can improve my question in any way.
//Login back-end
router.post('/login', (req, res, next) => {
if(validUser(req.body)) {
User
.getOneByEmail(req.body.email)
.then(user => {
if(user) {
bcrypt
.compare(req.body.password_digest, user.password_digest)
.then((result) => {
if(result) {
const isSecure = process.env.NODE_ENV != 'development';
res.cookie('user_id', user.id, {
httpOnly: true,
secure: isSecure,
signed: true
})
res.json({
message: 'Logged in'
});
} else {
next(new Error('Invalid Login'))
}
});
} else {
next(new Error('Invalid Login'))
}
});
} else {
next(new Error('Invalid Login'))
}
});
//Allow CORS index.js
app.use(
cors({
origin: "http://localhost:3000",
credentials: true
})
);
//Login client side (React.js)
loginUser(e, loginEmail, password) {
e.preventDefault();
let email = loginEmail;
let password_digest = password;
let body = JSON.stringify({ email, password_digest });
fetch("http://localhost:5656/api/login", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
credentials: "include",
body
})
.then(response => response.json())
.then(user => {
console.log(user);
});
}
You should be secure of set "credentials" in the server and in app.
Try to set on you index.js or app.js server side this:
app.use(function(req, res, next) {
res.header('Content-Type', 'application/json;charset=UTF-8')
res.header('Access-Control-Allow-Credentials', true)
res.header(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept'
)
next()
})
and in you client site add options like this:
let axiosConfig = {
withCredentials: true,
}
export async function loginUser(data) {
try {
const res = await axios.post(
`${URL}:${PORT}/${API}/signin`,
data,
axiosConfig
)
return res
} catch (error) {
console.log(error)
}
}
Edit
To set "credentials" in server we need this line:
res.header('Access-Control-Allow-Credentials', true)
This would let you handle credentials includes in headers.
You also have to tell to axios to set credentials in headers with:
withCredentials: true
Do not forget to adjust cors middleware.
Your node.js express code
const express = require("express");
const cors = require('cors')
const app = express();
app.use(cors(
{
origin: 'http://localhost:3000',
optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
}
));
app.use(function(req, res, next) {
res.header('Content-Type', 'application/json;charset=UTF-8')
res.header('Access-Control-Allow-Credentials', true)
res.header(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept'
)
next()
})
app.get("/auth", function(req, res){
res.cookie('token', 'someauthtoken')
res.json({id: 2});
});
app.listen(3030);
Your front-end code
import React, { useEffect } from 'react';
import axios from 'axios';
async function loginUser() {
try {
const res = await axios.get(
'http://localhost:3030/auth',
{
withCredentials: true,
}
)
return res
} catch (error) {
console.log(error)
}
}
function App() {
useEffect(() => {
loginUser();
}, [])
return (
<div>
</div>
);
}
export default App;
It is because you set httpOnly: true.
This will block the visibility to client side, like reading from javaScript document.cookie().
You can solve this by turn it off.
If you can't see your cookie in the browser, I think it is because you're setting hhtpOnly to true in the cookie's options.
cookie.httpOnly
Specifies the boolean value for the HttpOnly Set-Cookie attribute. When truthy, the HttpOnly attribute is set, otherwise it is not. By default, the HttpOnly attribute is set.
Note: be careful when setting this to true, as compliant clients will not allow client-side JavaScript to see the cookie in document.cookie
res.cookie('user_id', user.id, {
httpOnly: false, // try this
secure: isSecure,
signed: true
})
You need to configure cors in your backend server first.
First, install cors using npm i cors then in your express server add this line of code:
app.use(cors({
origin: "YOUR FRONTEND SITE URL HERE",
credentials: true,
}));
Then, in your frontend app where you are sending GET/POST requests to your backend, make sure to add in your request
If you've used fetch:
const res = await fetch('BACKEND SERVER URL', {
credentials: "include",
// other objects
});
If axios is used:
const res = await axios.post('BACKEND SERVER URL',
{ withCredentials: true },
// other objects,
);
This will solve the problem of storing cookies in frontend sent from backend.

Resources