Problems with API upon setting up Express JS on my ReactJS project - node.js

I am working on a little project here and I ran into an issue after hooking up "register" and "login".
I did this through NodeJS with Express.
The error I am having is:
Access to XMLHttpRequest at 'api' from origin 'http://localhost:3000' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
That appears in the console whenever I try to fetch the products from the API. I do not get this error if I haven't logged in to an account, but if I have logged in to an account that happens.
Here is my Nodejs code:
const express = require("express");
const mysql = require("mysql");
const cors = require("cors");
const bodyParser = require("body-parser");
const cookieParser = require("cookie-parser");
const session = require("express-session");
const bcrypt = require("bcrypt");
const saltRounds = 10;
const app = express();
app.use(
cors({
origin: ["http://localhost:3000"],
methods: ["GET", "POST"],
credentials: true,
})
);
app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(
session({
key: "",
secret: "",
resave: false,
saveUninitialized: false,
cookie: {
expires: 60 * 60 * 24,
},
})
);
app.use(express.json());
const db = mysql.createConnection({
user: "",
host: "",
password: "",
database: "",
});
app.post("/register", (req, res) => {
const firstName = req.body.firstName;
const lastName = req.body.lastName;
const username = req.body.username;
const phone = req.body.phone;
const password = req.body.password;
const email = req.body.email;
bcrypt.hash(password, saltRounds, (err, hash) => {
db.query(
"INSERT INTO `accounts`(`firstName`, `lastName`, `username`, `password`, `email`, `phone`) VALUES (?,?,?,?,?,?)",
[firstName, lastName, username, hash, email, phone],
(err, result) => {
console.log(err);
console.log(result);
}
);
});
});
app.get("/login", (req, res) => {
if (req.session.user) {
res.send({ loggedIn: true, user: req.session.user });
} else {
res.send({ loggedIn: false });
}
});
app.post("/login", (req, res) => {
const email = req.body.email;
const password = req.body.password;
let sql = `SELECT * FROM accounts WHERE email="${email}"`;
db.query(sql, (err, result) => {
try {
bcrypt.compare(password, result[0].password, (err, compResult) => {
if (err) throw err;
if (compResult) {
req.session.user = result;
res.send(compResult);
} else if (!compResult) {
res.send({ message: "Incorrect Password or Email!" });
}
});
} catch (err) {
res.send({ message: "Email does not exist!" });
}
});
});
Let me know if there is anything else you need!

Related

req.session keeps returning undefined

I am new to cookies and session in express and I have a problem I don't understand how to solve. I make a simple user login system which communicate with DB. My login call works fine, but when I try to recuperate the value in req.session.user, it always return undefined when I call it in /getevents or /addevent.
const express = require("express");
const mysql = require("mysql");
const cors = require("cors");
const cookieParser = require("cookie-parser");
const session = require("express-session");
const bcrypt = require("bcrypt");
const saltRounds = 10;
const app = express();
app.use(express.json());
app.use(
cors({
origin: ["http://localhost:3000"],
methods: ["GET", "POST"],
credentials: true,
})
);
app.use(cookieParser());
app.use(
session({
key:"userId",
secret: "123123123",
resave: true,
saveUninitialized: true
}));
const db = mysql.createConnection({
database: 'defaultdb',
host: "dbhost.com",
port: 12345,
user: "db_user",
password: "password"
});
app.post("/login", (req, res) => {
const username = req.body.username;
const password = req.body.password;
db.query(
"SELECT * FROM user WHERE username = ?;",
[username],
(err, result) => {
if (err) {
res.send({ err: err });
}
if (result.length > 0) {
bcrypt.compare(password, result[0].password, (error, response) => {
if (response) {
req.session.userId = result[0].id;
res.send(result);
} else {
res.send({ message: "Invalid username / password !" });
}
});
} else {
res.send({ message: "Username does not exist !" });
}
}
);
});
app.get("/getevents", (req, res) => {
db.query(
"SELECT title, date FROM events WHERE user_id =?;",
req.session.userId,
(err, result) => {
if (err) {
console.log(err);
}
else {
res.send(result);
}
}
);
});
app.post("/addevent", (req, res) => {
db.query(
"INSERT INTO event (title,date,user_id) VALUES (" + req.body.title + ", " + req.body.date + ", " + parseInt(req.session.userId) + ")",
(err, result) => {
if (err) {
console.log(err);
}
else {
res.send(result);
}
}
);
})
After trying to resolve for a few hours I'm kind of out of ideas...

How to prevent myself from being constantly logged out from Heroku? (possibly express session problem)

I have a website project with frontend at Netlify and backend at Heroku. Currently, I use express session for recording login information. Just now, with about 40 users logging into the website at the same time, I started to be logged out by Heroku much more frequently and have the error message "Application error" displayed at my server site, like this.
I wonder if the phenomenon is caused by the large number of session information stored in my server after all the users log in at once (since I use express session), but honestly, I don't know how to transform from express to cookie session.
Also, I'm aware that there are quotas for the number of queries sent to the database, in this case ClearDB (MySQL) under Heroku, yet I am not banned from reconnecting with the server after logging in again to Heroku, so it may not be the problem.
How can I fix it? Thanks in advance!
This is my code in index.js (with some unrelated methods left out) in my website's server folder:
const express = require('express')
const mysql = require('mysql')
const cors = require('cors')
const session = require('express-session')
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser')
const mysqlStore = require('express-mysql-session')(session);
const port = 3010
const app = express()
app.use(express.json())
app.use(cors({
origin: ["https://xxx.netlify.app"],
methods: ["GET", "POST"],
credentials: true
}))
const options = {
host: "xxx.cleardb.net",
port: 3306,
user: "xxx",
password: "xxx",
database: "heroku_xxx",
createDatabaseTable: true,
schema: {
tableName: 'session_tab',
columnNames: {
session_id: 'session_id',
expires: 'expires',
data: 'data'
}
}
}
const sessionStore = new mysqlStore(options);
app.use(cookieParser())
app.use(bodyParser.urlencoded({extended: true}))
app.set('trust proxy', 1)
app.use(session({
key: "userId",
secret: "nosecret",
store: sessionStore,
resave: true,
saveUninitialized: false,
cookie: {
sameSite: "none",
secure: true,
httpOnly: true,
maxAge: 600 * 1000
}
}))
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "https://xxx.netlify.app");
res.setHeader(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
res.setHeader(
"Access-Control-Allow-Methods",
"GET, POST, PATCH, DELETE, OPTIONS"
);
res.setHeader('content-type', 'application/json');
next();
});
const db = mysql.createPool({
// create an instance of the connection to the mysql database
host: 'xxx.cleardb.net', // specify host name
user: 'xxx', // specify user name
password: 'xxx', // specify password
database: 'heroku_xxx', // specify database name
})
...
app.post('/login', (req, res) => {
const username = req.body.username
const password = req.body.password
console.log("username");
console.log(username);
console.log("password");
console.log(password);
db.query(
'SELECT * FROM user where username = ? AND password = ?',
[username, password],
(err, result) => {
console.log("result");
console.log(result);
if (err) {
res.send({ err: err })
}
if (result.length) {
req.session.user = result;
console.log("req.session.user (post /login)");
console.log(req.session.user);
if(result[0].role == "student") {
let name = result[0].lastname + result[0].firstname;
console.log(name);
req.session.userfullname = name;
console.log("req.session.userfullname");
console.log(req.session.userfullname);
db.query('SELECT * FROM contact where studentname = ?',
[name],
(err, result) => {
console.log("req.session.userteacherusername");
console.log(req.session.userteacherusername);
req.session.userteacherusername = result[0].username;
})
}
let output = req.session.user + req.session.userfullname + req.session.userteacherusername;
res.send(output);
req.session.save();
} else {
res.send({ message: 'Wrong username or password.' });
}
},
)
})
app.get('/login', (req, res) => {
console.log("req.session.user (get /login)");
console.log(req.session.user);
if(req.session.user) {
res.send({isLoggedIn: true, user: req.session.user})
} else {
res.send({isLoggedIn: false})
}
})
...
app.post('/logout', (req, res) => {
req.session.destroy(
function(err){
if(err){
res.send(err)
}else{
res.send("successfully logged out.")
}
}
);
})
...
app.listen(process.env.PORT || port, () => {
console.log('Successfully Running server at ' + port + '.')
});

Cannot set headers after they are sent to the client/ Server crashes with this when page refreshes

Made a Question a few days ago on here, thought I had it figured out, even accepted the answer, because it was right regardless. but now I have the Same issue, same error.
Heres the Error.
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:558:11)
at ServerResponse.header (/Users/apple/Documents/Web Dev/collab/Backend/node_modules/express/lib/response.js:771:10)
at ServerResponse.send (/Users/apple/Documents/Web Dev/collab/Backend/node_modules/express/lib/response.js:170:12)
at ServerResponse.json (/Users/apple/Documents/Web Dev/collab/Backend/node_modules/express/lib/response.js:267:15)
at /Users/apple/Documents/Web Dev/collab/Backend/routes/index.js:90:23
at processTicksAndRejections (internal/process/task_queues.js:93:5) {
code: 'ERR_HTTP_HEADERS_SENT'
}
Heres Index.js. Line 90 is at the very bottom,
# router.get("/", isAuth, (req, res)
const router = require("express").Router();
const passport = require("passport");
const bodyParser = require("body-parser");
const genPassword = require("../lib/passwordUtils").genPassword;
const connection = require("../config/database");
const mongoose = require("mongoose");
const User = mongoose.models.User;
const isAuth = require("./authMiddleware").isAuth;
// cors is needed with router.use else you have to put routes on the app.js
const cors = require("cors");
router.use(cors({ origin: "http://localhost:3001", credentials: true }));
// const isAdmin = require("./authMiddleware").isAdmin;
router.use(bodyParser.urlencoded({ extended: false }));
/**
* -------------- Post ROUTES ----------------
*
*/
router.post("/login", (req, res, next) => {
passport.authenticate("local", (err, user, info) => {
if (err) {
throw err;
} else if (!user) {
res.send("No User Exists");
} else {
req.logIn(user, (err) => {
if (err) throw err;
res.send(user);
return;
// console.log(req.user);
});
}
})(req, res, next);
});
router.post("/register", (req, res) => {
const saltHash = genPassword(req.body.repeatPassword);
const salt = saltHash.salt;
const hash = saltHash.hash;
const newUser = new User({
username: req.body.firstInput,
fName: "",
lName: "",
title: "",
hash: hash,
salt: salt,
});
newUser.save().then((user) => {});
res.sendStatus(200);
});
/**
* -------------- GET ROUTES ----------------
*
*/
router.post("/user", (req, res) => {
const fName = req.body.firstInput;
const lName = req.body.secondInput;
const title = req.body.repeatPassword;
const user = req.session.passport.user;
User.updateOne(
{ _id: user },
{ fName: fName, lName: lName, title: title },
function (err, result) {
if (err) {
res.sendStatus(401);
console.log(err);
} else {
res.sendStatus(200);
}
}
);
});
router.get("/", isAuth, (req, res) => {
const userMap = {};
User.find({}, function (err, users) {
users.forEach(function (user) {
userMap[user._id] = user;
});
return userMap;
})
.then((response) => {
res.status(200).json({ user: req.user, auth: true, response });
return;
})
.catch((err) => console.log(err));
});
module.exports = router;
Heres App.js
const express = require("express");
const app = express();
const mongoose = require("mongoose");
const session = require("express-session");
const passport = require("passport");
const crypto = require("crypto");
const routes = require("./routes");
const isAuth = require("./routes/authMiddleware").isAuth;
const connection = require("./config/database");
const cors = require("cors");
app.use(cors({ origin: "http://localhost:3001", credentials: true }));
const User = mongoose.models.User;
const bodyParser = require("body-parser");
const MongoStore = require("connect-mongo")(session);
require("dotenv").config();
app.use(express.json());
// app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.urlencoded({ extended: true }));
const sessionStore = new MongoStore({
mongooseConnection: mongoose.connection,
collection: "sessions",
});
app.use(
session({
secret: "zdfbdaf",
resave: true,
saveUninitialized: true,
store: sessionStore,
cookie: {
cookie: { secure: false },
maxAge: 1000 * 60 * 60 * 24,
},
})
);
require("./config/passport");
app.use(passport.initialize());
app.use(passport.session());
app.use("/", routes);
app.listen(3000);
heres authMiddleware.js
module.exports.isAuth = (req, res, next) => {
if (req.isAuthenticated()) {
next();
// res.status(200).json({ user: req.user, auth: true });
} else {
res.status(401).json({ auth: false });
}
};
// module.exports.isAdmin = (req, res, next) => {
// if (req.isAuthenticated() && req.user.admin) {
// next();
// } else {
// res.status(401).json({ msg: 'You are not authorized to view this resource because you are not an admin.' });
// }
// }
Heres passport.js
const passport = require("passport");
const LocalStrategy = require("passport-local").Strategy;
const connection = require("./database");
const mongoose = require("mongoose");
const User = mongoose.models.User;
const validPassword = require("../lib/passwordUtils").validPassword;
const cors = require("cors");
passport.use(cors({ origin: "http://localhost:3001" }));
const customFields = {
usernameField: "username",
passwordField: "password",
};
passport.use(
new LocalStrategy(customFields, (username, password, done) => {
User.findOne({ username: username })
.then((user) => {
if (!user) {
console.log("No user");
return done(null, false);
} else {
const isValid = validPassword(password, user.hash, user.salt);
if (isValid) {
console.log("Logged in");
return done(null, user);
} else {
console.log("Wrong Password");
return done(null, true);
}
}
})
.catch((err) => {
done(err);
});
})
);
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => {
done(err, user);
})
.then((user) => {
done(null, user);
})
.catch((err) => done(err));
});
It only crashes half the time, kind of? It works at first, until you refresh the page. I am at a loss. Had someone in the discord also not know the issue. I'm begging for some help here. I'm losing my mind.
its because you are calling done twice once after finding the user
and second after .then block in passport.deserializeUser function
this will work:
passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => {
done(err, user)
});
});

Passport req.login doesn't create req.user

i am trying to develop a login system with React,Node,Mysql,Express and Passport but i have encountered this problem. After calling req.login and passing it the userID, when i go to the route where i check for the req.user it says undefined. Here is my code for the server side.
const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");
const app = express();
const session = require("express-session");
const { PORT = 8000 } = process.env;
const bcrypt = require("bcrypt");
const saltRounds = 10;
const cookieParser = require("cookie-parser");
const passport = require("passport");
var LocalStrategy = require('passport-local').Strategy;
const mysql = require("mysql");
/app.options("*", cors());
app.use(cors());
app.use(express.json()) // for parsing application/json
app.use(express.urlencoded({ extended: true })) // for parsing application/x-www-form-urlencoded
// app.use(cookieParser());
app.use(
session({
secret: "keyboard cat",
resave: false,
saveUninitialized: false
// cookie: { secure: false }
})
);
app.use(passport.initialize());
app.use(passport.session());
const connection = mysql.createConnection({
host: "localhost",
user: "root",
password: "qwertyhnjkl",
database: "login"
});
connection.connect(err => {
if (err) {
console.error("Error connection to database");
}
else console.log("Database connected");
});
app.get('/',function (req,res){
console.log(req.user);
console.log(req.isAuthenticated())
res.send('hello world')
});
app.post("/register", (req, res) => {
const { name, username, email, password } = req.body;
console.log(req.body);
bcrypt.hash(password, saltRounds, function(err, hash) {
connection.query(
`insert into users(Name,Username,Email,Password) values('${name}','${username}','${email}','${hash}')`,
function(error) {
if (error) console.error(error);
}
);
connection.query("SELECT LAST_INSERT_ID() as userID", (error,results,fields) =>
{
if (error) throw error;
console.log(results)
const userID = results[0].userID;
console.log("userid in query: " + userID);
req.login(userID, function(err) {
if(err) res.send(err);
else{
console.log("req.user in req.login: " + req.user)
console.log("isAuthenticated: "+ req.isAuthenticated())
console.log(req.session )
console.log('Logged in succesfully')
res.send("Logged in succesfully");
}
});
});
});
});
And this is how i handle the form in react:
submitRegister(event) {
event.preventDefault();
const data = this.state.data
axios.post("http://localhost:8000/register", {
name: data.name,
username: data.username,
email: data.email,
password: data.password
})
.then(response => {
console.log(response);
if(response.data){
console.log('Succesful signup');
this.setState({ //redirect to login page
redirectTo: '/'
})
}
}).catch(error => {
console.log("Sign up to server failed");
console.log(error)
});
}
After i request the '/' of the server and check for the session in Application->Cookies->localhost there is no session.
The insertion is well done. I get the username email hashed password in my database. i get the right userID i even get the console.log in serialize function with the right userID(the last one introduced)
req.user in req.login: 47
isAuthenticated: true
Session {
cookie:
{ path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true },
passport: { user: 47 } }
Logged in succesfully
serialize 47
This is what i get in the console when requesting the route /register from the server. Now when i go for localhost:8000 it says req.user is undefined and isAuthenticated false.
Looks like cors() was the issue here. After removing it and using proxy in package.json solved the issue.

How to test express-session type sessions in nodejs using postman?

I have a nodejs backend with sessions made using express-session npm module. I want to test the sessions using postman.
What I want is a user should be allowed to access the users list via the /getUsers route only if he is currently in a session. But what is happening is when I test the backend using postman even after logging in the user is unable to access the users using the /getUsers route. Is this something to do with postman?
Here is my app.js
const express = require("express");
const app = express();
const authRoutes=require('./routes/auth');
const mongoose=require('mongoose');
const bodyParser = require("body-parser");
require("dotenv").config();
const nodemailer = require("nodemailer");
const session = require('express-session');
const RedisStore = require('connect-redis')(session);
const cors = require('cors');
app.use(cors({
origin:['http://localhost:8080'],
methods:['GET','POST'],
credentials: true // enable set cookie
}));
app.use(
// Creates a session middleware with given options.
session({
name: 'sid',
saveUninitialized: false,
resave: false,
secret: 'sssh, quiet! it\'s a secret!',
cookie: {
httpOnly: true,
maxAge: 1000 * 60 * 60 * 2,
sameSite: true,
secure: true
}
})
);
mongoose.connect(process.env.LOCAL_MONGO_URI,{useNewUrlParser:true},function (err) {
if (err) throw err
console.log("Connected to local mongo db database");
});
app.get("/",(req,res)=> {console.log("A request was made to /")
console.log("/GET called");
});
app.use(bodyParser.json());
app.use("/",authRoutes);
const port = process.env.PORT||8080
app.listen(port,()=> {
console.log("Hello world");
})
Here is my routes/auth.js:
const express = require("express");
const {
signup,login,verifyemail,requiresLogin,getUsers,logout
} = require("../handler/auth")
const router = express.Router();
router.post("/signup",signup);
router.post("/login",login);
router.get("/verifyemail/:token",verifyemail);
router.get("/getUsers",requiresLogin,getUsers);
router.get("/getUsers",requiresLogin,getUsers);
router.get("/logout",requiresLogin,logout);
module.exports=router;
Here is my handler/auth.js
const User = require("../models/user");
const bcrypt = require('bcrypt');
const crypto = require('crypto');
exports.signup = async (req, res) => {
const email = req.body.email;
User.findOne({email},function(err,user){
if(err) return res.status(500).json({message:err.message});
else if(user) return res.status(403).json({"message":"User exists"});
const password = req.body.password;
const name = req.body.name;
bcrypt.hash(password, 10)
.then(async function(hashed_password) {
const user = await new User({email,name,hashed_password});
user.emailVerificationToken = crypto.randomBytes(20).toString('hex');
user.emailVerificationTokenExpires = Date.now() + 3600000*24;
await user.save(function(err) {
if(!err) {
const resetURL = `http://${req.headers.host}/verifyemail/${user.emailVerificationToken}`;
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const msg = {
from: 'admin#pinclone.com',
to: email,
subject: 'Email verification link',
html: `Verify your email here to login to your account`,
};
sgMail.send(msg);
return res.json({message:"verify email address to login"});
}
return res.status(500).send({ message: err.message });
});
})
.catch(function(error){
res.status(500).send({message:error.message});
});
});
};
exports.login = (req,res) => {
const email = req.body.email;
const password = req.body.password;
User.findOne({email},function(err,user) {
if(err) return res.status(500).json({message:err.message});
if(!user) return res.status(403).json({"message":"User does not exists"});
bcrypt.compare(password,user.hashed_password,(err,result) => {
if(result) {
if(user.isVerified)
return res.status(200).json({"message":"successfully logged in"});
else
return res.status(403).json({"message":"user is not verified"});
}
else return res.status(403).json({message: "email address password do not match"});
});
});
};
exports.verifyemail = async (req,res) => {
User.findOneAndUpdate({emailVerificationToken: req.params.token,emailVerificationTokenExpires: { $gt: Date.now() }}, {$set:{isVerified:true}}, {new: true}, (err, user) => {
if (err) {
res.status(403).send({message:"Link invalid or expired"});
// res.status(500).send({message:"Something wrong when updating data!"});
}
if(user) {
res.status(200).send({"message":"email verification successful you can login now!"});
}
});
};
exports.requiresLogin = (req, res, next) => {
if (req.cookies.sid) {
return next();
} else {
var err = new Error('You must be logged in to view this page.');
err.status = 401;
return next(err);
}
};
exports.logout = (req, res) => {
res.clearCookie('sid');
res.send("logout success");
};
exports.getUsers = (req,res) => {
User.find({},function(err,users){
res.send(users);
});
};
You can set session in tab Header with your key.
You can read https://www.toolsqa.com/postman/sessions-in-postman/ for more detail.
You should read at How to use Sessions in Postman? part.

Resources