I am using Node JS on serverside and React on client side. On successful auth when i try to use res.cookie and set a cookie. On client side however the Cookie only shows up in Network tab and does not get set in application tab. I am using axios for making the request and have even set the credentials header to include since I am using cors. Here is my code below
router.post("/", (req, res) => {
console.log(req);
const email = req.body.email;
const password = req.body.password;
loginService.login(email, password, (userPublicData, token, err) => {
if (err) {
res.status(401);
res.send({ user: null, error: err });
} else {
res.status(200);
res.cookie("jwt", token);
res.send({ user: userPublicData, error: err });
}
});
});
Here is my client side function
async function authenticateUser() {
console.log(values);
axios.defaults.headers.common["credentials"] = "include";
axios
.post("http://localhost:8080/api/login", values)
.then(response => response.data)
.then(dataJson => {
sessionStorage.setItem("userData", dataJson);
props.history.push("/admin");
})
.catch(err => {
console.error("Auth error", err);
});
}
The cookie appears in network tab but doesnot get set in the application cookies. Some help would be much appreciated
Related
Here im making a request to from the frontend to backend:
await axios.post("http://localhost:5000/users/signin", data) // <- sending wrong data
.then()
.catch((err) => console.log(err.message)); // <-- here the response is 404
Here i make the request to the mongodb:
const signin = async (req, res) => {
const { email } = req.body;
try {
const existingUser = await User.findOne({ email });
if (!existingUser) return res.status(404).json({ message: "User not found." });
};
router.route("/signin").post(signin)
Bacically i want when the user sends wrong data i want the err.message i get to be "User not found." but it is Request failed with status code 404.
Why?
Because err.message is not where the JSON data is stored; Instead use err.response.data (err.response is the actual response from the web server, err is what is raised by the axios.post() failing)
I am currently stuck trying to implement a refresh token with express middleware, react and JWT. The problem I am having is I need to pass the refreshed token back to the client from the middleware function. I have tried using res.locals.variableName and also res.set, but once the middleware function is finished and next() is called, I am responding with res.json in my route, which I think is overwriting anything I set in the response from the middleware. How can I return this refresh token to client side while still being able to call next()?
app.all('*', function (req, res, next) {
const headerToken = req.headers.token;
const refreshToken = req.headers.refreshtoken;
const isVerifiedPath = verifyPaths(unauthorizedPaths, currentPath);
if (isVerifiedPath) {
next()
}
else {
jwt.verify(headerToken, process.env.KEY, async (err, data) => {
if (err) {
if (err.expiredAt) { // expired web token
jwt.verify(refreshToken, process.env.KEY, async (err, data) => {
if (data) {
const User = require('./models/User');
const user = await User.query().findById(data.user.id);
const token = jwt.sign({ user }, process.env.KEY, { expiresIn: 5 });
req.user = user;
res.locals.varName = token; // I would like this to be accessible from the response my api returns
next();
}
})
}
else {
return res.status(401).json({ err: 401 });
}
}
else {
req.user = data.user;
next();
}
});
}
});
The solution to my problem was to pass the token through headers like this. I wasn't able to view the token client side because I was not exposing the header (line 2).
res.set('x-token', token);
res.set('Access-Control-Expose-Headers', 'x-token');
So I have a React frontend, and Node backend as my api connecting to mysql database. Everything works perfectly locally.
Now I have deployed to a c-panel VPS.
Front end loads as it should.
The back-end is listening, and prints out the data as it should if I type my IP address with routes into the address bar on a browswer.
However, I can get it to work typing the "domain-name + the routes". Can anyone tell me what's going on, and how to configure this is cPanel properly? I've spent days going in circles on this, and the hosting company support is no help at all.
here is a sample fetch call:
componentDidMount() {
fetch('/api/clients/all')
.then(res => {
if (!res.ok) {
throw new Error();
}
return res.json();
})
.then((result) => {
this.setState({
clients: result.sort((a, b) => a.client.localeCompare(b.client)),
});
console.log(result);
})
.catch(error => {
console.log(error);
})
.then(
fetch(`/api/contacts/all`)
.then(res => {
if (!res.ok) {
throw new Error();
}
return res.json();
})
.then((result) => {
this.setState({ contacts: result });
console.log(result);
})
.catch(error => {
console.log(error);
})
);
}
This is my server file with the routes in it.... I can't understand where my configuration is wrong. I think it may even be some cpanel configuration with the server, and not necessarily my code. Any help is appreciated.
const express = require('express');
const mysql = require('mysql2');
const cors = require('cors');
const connection = mysql.createPool({
connectionLimit: 10,
host : 'localhost',
user : 'root',
password : 'C5pkhi6r12!',
database : 'ppr'
});
const app = express();
app.use(express.json());
app.use(express.urlencoded({extended: false}));
app.use(cors());
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
next();
});
app.get('/api/clients/all', function (req, res) {
// Connecting to the database.
connection.getConnection(function (err, connection) {
// Executing the MySQL query (select all data from the 'handbook' table).
connection.query("SELECT * FROM clients", function (error, results) {
// If some error occurs, we throw an error.
if (error) throw error;
// Getting the 'response' from the database and sending it to our route. This is where the data is.
console.log(results);
res.json(results);
});
connection.release();
});
});
app.get('/api/contacts/all', function (req, res) {
// Connecting to the database.
connection.getConnection(function (err, connection) {
// Executing the MySQL query (select all data from the 'handbook' table).
connection.query("SELECT * FROM contacts", function (error, results) {
// If some error occurs, we throw an error.
if (error) throw error;
// Getting the 'response' from the database and sending it to our route. This is where the data is.
// console.log(results);
res.json(results);
});
connection.release();
});
});
// Starting our server.
app.listen(8080, "0.0.0.0", () => {
console.log('Listening on port http://localhost:8080');
});
I might be late to answer, but this is how I did.
Add "Hostname": "https://YOURDOMAIN.XYZ" to package.json in react app.
Build your react app, and upload it to public_html
Use nodejs tool of cpanel.
Don't do app.listen(port, ........). Just use callback or leave it to app.listen()
I have worked with Cors before in a MEAN stack app. And it perfectly played its role. However, now I am transitioning to the MERN stack, I keep getting this error despite using CORS in the backend:
Access to XMLHttpRequest at 'http://localhost:5000/api/users/register' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Register.js:43 Error: Network Error
at createError (createError.js:16)
at XMLHttpRequest.handleError (xhr.js:83)
xhr.js:178 POST http://localhost:5000/api/users/register net::ERR_FAILED
So for some reason, CORS isn't doing what it's supposed to do?
Here's the main code:
Backend/server.js
// Use routes
app.use("/api/users", users);
app.use("/api/profile", profile);
app.use("/api/posts", posts);
// Use Cors
app.use(Cors());
//process.env.Port is for Heroku
const port = process.env.Port || 5000;
// `` ES6 Template literal is used so that we can put a variable inside the String
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
Backend/routes/api/users.js
// #route POST api/users/register
// #desc Register user
// #access Public
router.post("/register", (req, res) => {
// Before we do anything, we will validate the data
const { errors, isValid } = validateRegisterInput(req.body);
// Check validation
if (!isValid) {
return res.status(400).json(errors);
}
// First, we will use mongoose to find if the email exists
// Because we don't want someone to register with an email that's already in the db
// req.body.email is possible thanks to bodyParser module
User.findOne({ email: req.body.email }).then(user => {
if (user) {
errors.email = "email already exists";
return res.status(400).json({
errors
});
} else {
const avatar = gravatar.url(req.body.email, {
s: "200", //Size
r: "pg", //Rating
d: "mm" //Default
});
// new Modelname({data})
const newUser = new User({
name: req.body.name,
email: req.body.email,
// This will be the avatar URL
//avatar: avatar,
// Since they are the same with ES6 we can do just avatar
// But it doesn't know what avatar is, for this we will use gravatar
avatar,
password: req.body.password
});
bcrypt.genSalt(10, (err, salt) => {
// If there's an error it'll give us an error, if not it'll give us a hash
// A hash is what you want to store in the database
bcrypt.hash(newUser.password, salt, (error, hash) => {
if (error) {
throw error;
}
newUser.password = hash;
newUser
.save()
.then(user => res.json(user))
.catch(err => {
console.log(err);
});
});
});
}
});
});
Frontend/src/components/auth/Register.js
axios
.post("http://localhost:5000/api/users/register", newUser)
.then(res => {
console.log(res.data);
})
.catch(err => console.log(err));
You have to use cors before using the routes. If you don't do this and since your route handlers don't call next(), cors never has a chance to manipulate your response.
// Use Cors
app.use(Cors());
// Use routes
app.use("/api/users", users);
app.use("/api/profile", profile);
app.use("/api/posts", posts);
Open it in dev mode:
app.use(
cors({
origin: (origin, callback) => callback(null, true),
credentials: true
})
);
When i trying to run my API in postman it is working fine and sessions are getting maintained. But when i am trying to run it from UI Part the login session is not working.
This is my Login API from where i am login into
app.post('/user/login', (req, res, next) => {
const body = req.body;
let email = body.email;
let password = body.password;
const userDetails = db.collection(userProfiles);
userDetails.findOne({email: email}, function (err, user) {
if (err) {
return next(err);
} else if (!user) {
return res.status(400).send({
status: 'error',
message: 'user does not exist'
});
} else {
if (user.password == password) {
user_object = user;
req.session.user = user;
return res.send({
user_obj: user,
status: 'success',
message: 'Successfully logged in'
});
} else {
return res.status(400).send({
status: 'error',
message: 'Wrong Password'
})
}
}
return res.send(user);
});
});
This is my session API from where i am sending user req.session.user on calling this api
app.get('/user/dashboard', function (req, res) {
if (!req.session.user) {
return res.status(400).send({
data:'need to be logged in'
});
}
return res.status(200).send({
data:req.session.user
});
});```
The below is the javascript file from where i am trying to call the user stores in req.session.user
`
async function fetchUserId(){
let cookie = document.cookie;
let res = await fetch('http://127.0.0.1:8080/user/dashboard',
{redirect: 'follow',
headers:{
"Cookie":cookie
}});
let userJson = await res.json();
console.log(res);
console.log(userJson);
//return userJson;
};
`
when i hit the login API from Postman it is maintaining session and working fine but when i do the same from UI from browser it is giving error status 400 every time.
You can do a
fetch(url, options).then(function(res) { console.log(res} )
and
app.get('/user/dashboard', function (req, res) {
console.log(req.headers)
if (!req.session.user) {
return res.status(400).send({
data:'need to be logged in'
});
}
return res.status(200).send({
data:req.session.user
});
});
To check is the cookie really there and where is the user object.
And you can check your browsers dev console to see if the cookie is updating.
I see that is fetch request you put a cookie in your header. But than at the API you are looking for a user at req.session.user. Although the cookie is in req.header["Cookie"].