Express-session not saving - node.js

I'm now to nodejs and have been trying to find a solution for this problem but all of the solutions haven't been working.
req.session.user is always return undefined. it sets if I set it within a function but as soon as it exits the function it becomes undefined again. It works find from app.get/post but not when using a router
server.js
const express = require('express');
const session = require('express-session');
const cors = require('cors');
const bodyParser = require('body-parser');
require('dotenv').config();
const app = express();
const dbo = require('./database');
app.use(cors());
const sessionMiddleware = session({
secret: "ei_13495781kam",
resave: false,
saveUninitialized: true,
cookie: {
secure: false,
maxAge: 6000
}
});
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());
app.use(sessionMiddleware);
const userRoute = require('./routes/user-route');
app.use('/user', sessionMiddleware, userRoute);
app.route('/').get((req, res) => {
req.session.user = {
loggedIn: false,
id: ''
};
});
const port = process.env.PORT || 5000;
app.listen(port, () => {
console.log('App is running on port ' + port);
dbo.connectToServer((err) => {
console.log(err);
})
})
user-route.js
const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const dbo = require('../database');
const session = require('express-session')
const {response} = require("express");
const objectId = require('mongodb').ObjectId;
router.route('/register').post((req, res) => {
console.log('Hello World');
if(typeof req.session.user === 'undefined' || !req.session.user.loggedIn) {
let db_connection = dbo.getDb();
bcrypt.hash(req.body.password, 10)
.then((hashedPswd) => {
req.body.password = hashedPswd
db_connection.collection('users').insertOne(req.body, (err, response) => {
if(err) throw err;
req.session.user = {
loggedIn: true,
id: response.insertedId
};
res.json({loggedIn: true});
})
})
}
})
router.route('/session').get((req, res) => {
if(typeof req.session.user === 'undefined') {
req.session.user = {
loggedIn: false,
id: ''
}
res.json({sessionValid: false})
} else {
res.json({sessionValid: req.session.user.loggedIn})
}
});
router.route('/login').post((req, res) => {
let db_connection = dbo.getDb();
const searchQuery = {
username: req.body.username
};
db_connection.collection('users').findOne(searchQuery, (err, response) => {
if(err) throw err;
if(response) {
bcrypt.compare(req.body.password, response.password, (err, pResponse) => {
if(pResponse) {
req.session.user = {
loggedIn: true,
id: objectId(response._id),
}
req.session.save();
console.log("1 " + JSON.stringify(req.session.user));
res.json({loggedIn: true});
} else {
res.json({loggedIn: false});
}
})
}
})
console.log("2 " + req.session.user);
})
module.exports = router;
I've tried setting it if it's undefined also tried saving it manually or passing the middle ware into the app.use(/route/)

maxAge: 6000
Your cookie has a maxAge of 6 seconds... are you sure you made a request within six seconds of the server being started and still produced an error?

Related

Express-session data returns undefined in react & nodejs application

When i tried to use it with react app i can not reach the value. I use sequelize orm and mysql database. I want to send the session information to the react side when the user logs in
app.js file:
const express = require('express')
const dotenv = require("dotenv")
const app = express()
const body_parser = require("body-parser");
const cookieParser = require("cookie-parser")
const session = require('express-session')
const cors = require("cors")
dotenv.config()
app.use(cors())
const SequelizeStore = require("connect-session-sequelize")(session.Store);
const adminRoute = require("./routes/admin")
const locals = require("./middlewares/locals")
app.use(cookieParser())
app.use(express.urlencoded({ extended: false }))
app.use(body_parser.json())
const sequelize = require("./data/db")
app.use(session({
secret: "hello world",
resave: false,
saveUninitialized: false,
cookie: {
maxAge: 1000 * 60 * 60 * 24
},
store: new SequelizeStore({
db: sequelize
})
}))
app.use(locals);
app.use(adminRoute)
const dummy = require("./data/dummy-data")
async function x() {
// await sequelize.sync({ force: true })
// await dummy()
}
x()
app.listen(process.env.PORT, () => {
console.log(`Server running on Port: ${process.env.PORT}`)
})
locals.js file:
module.exports = (req, res, next) => {
res.locals.auth = req.session.auth
console.log("auth : ", res.locals.auth)
next();
}
admin.js routes:
router.get("/api/session", async (req, res) => {
res.json({ isAuth: res.locals.isAuth });
});
router.post("/login", async (req, res) => {
const { email, password } = req.body
console.log(req.body)
try {
const user = await Users.findOne({
where: {
email: email
}
})
if (!user) {
return res.status(404)
}
const match = await bcrypt.compare(password, user.password)
console.log("match:", match)
if (match) {
req.session.isAuth = 1
return res.status(200).send({ message: "login successful" })
}
else {
req.session.isAuth = 0
return res.status(404)
}
}
catch (err) {
console.log(err)
}
})
React Login.js:
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const login = async (e) => {
e.preventDefault()
const response = await axios.post("http://localhost:5000/login", { email: email, password: password })
console.log(response)
if(response.status === 200){
const response2 = await axios.get("http://localhost:5000/api/session")
console.log(response2)
}
}
Login.js first response = data: {message: 'login successful'}
Login.js second response = data: {}
If i try to react http://localhost:5000/login by hand on the browser auth sets as true. But when i refresh react side it sets undefined again.

Getting error TypeError: next is not a function

I'm getting error "TypeError: next is not a function" while trying to authenticate dashboard route in nodejs.
I am trying to make and CRUD app with node and mongoDB suing these modules express ejs mongoose bcryptjs passport passport-local.
Getting this error when I submit login form.
I am new in nodejs, Please help me
Thanks in advance.
auth/protect.js file
const protectRoute = (req, res, next) =>{
if (req.isAuthenticated()) {
return next();
}
console.log('Please log in to continue');
res.redirect('/login');
}
const allowIf = (req, res, next) =>{
if (!req.isAuthenticated()) {
return next();
}
res.redirect('/dashboard');
}
module.exports = {
protectRoute,
allowIf,
};
routes/login.js file
const express = require("express");
const {
registerView,
loginView,
registerUser,
loginUser,
} = require("../controllers/loginController");
const { dashboardView } = require("../controllers/dashboardController");
const { protectRoute } = require("../auth/protect");
const router = express.Router();
router.get("/register", registerView);
router.get("/login", loginView);
router.get("/", loginView);
//Dashboard
router.get("/dashboard", protectRoute, dashboardView);
router.post("/register", registerUser);
router.post("/login", loginUser);
module.exports = router;
server.js file
const express = require("express");
const cors = require("cors");
const app = express();
const mongoose = require('mongoose');
const session = require('express-session');
const passport = require("passport");
const { loginCheck } = require("./auth/passport");
var corsOptions = {
origin: "http://localhost:8081"
};
app.use(cors(corsOptions));
const db = require("./models");
db.mongoose
.connect(db.url, {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => {
console.log("Connected to the database!");
})
.catch(err => {
console.log("Cannot connect to the database!", err);
process.exit();
});
app.set('view engine', 'ejs');
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(session({
secret:'oneboy',
saveUninitialized: true,
resave: true
}));
app.use(passport.initialize());
app.use(passport.session());
// simple route
app.use('/', require('./routes/login'));
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}.`);
});
I have missed to call a function loginCheck(passport); in my server.js file that's why I was getting error during login form submission.
server.js starting code
const express = require("express");
const cors = require("cors");
const app = express();
const mongoose = require('mongoose');
const session = require('express-session');
const passport = require("passport");
//var LocalStrategy = require('passport-local').Strategy;
const { loginCheck } = require("./auth/passport");
loginCheck(passport);
........................................
I was added this function in auth/passport.js file
passport.js
//js
const bcrypt = require("bcryptjs");
LocalStrategy = require("passport-local").Strategy;
//Load model
const User = require("../models/User");
const loginCheck = passport => {
passport.use(
new LocalStrategy({ usernameField: "email" }, (email, password, done) => {
//Check customer
User.findOne({ email: email })
.then((user) => {
if (!user) {
console.log("wrong email");
return done();
}
//Match Password
bcrypt.compare(password, user.password, (error, isMatch) => {
if (error) throw error;
if (isMatch) {
return done(null, user);
} else {
console.log("Wrong password");
return done();
}
});
})
.catch((error) => console.log(error));
})
);
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
User.findById(id, (error, user) => {
done(error, user);
});
});
};
module.exports = {
loginCheck,
};
If you are trying to use next() in normal function then it will give an error
const allowIf = (req, res, next) =>{
return next(); // throw an error - TypeError: next is not a function
}
allowIf();
So use next() as a Callback argument to the middleware function. It will work fine in this case. Try this:
const protectRoute = (req, res, next) =>{
console.log('protectRoute');
return next();
}
app.get('/', protectRoute);

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.

"TypeError: Cannot read property 'email' of undefined" in nodejs authentication system

I'm trying to run an authentication module using express-session and passport.
server.js
var express = require("express");
var session = require('express-session');
var connection = require('./config');
var bodyParser = require('body-parser');
var passport = require('passport');
const redis = require('redis');
const redisStore = require('connect-redis')(session);
const client = redis.createClient();
var app = express();
var router = express.Router();
var authController=require('./controllers/auth-controller');
var regController=require('./controllers/reg-controller');
app.use(session({secret: 'secret', store: new redisStore({ host: 'localhost', port: 8000, client: client,ttl : 260}), saveUninitialized: true, resave: true}));
app.use(passport.initialize());
app.use(passport.session());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
router.get('/',(req,res) => {
let sess = req.session;
if(sess.email){
return res.redirect('/admin');
}
res.sendFile( __dirname + '/' + 'index.html' );
})
router.post('/login',(req,res) => {
sess = req.session;
sess.email = req.body.email;
res.end('done');
});
router.get('/admin',(req,res) => {
sess = req.session;
if(sess.email) {
res.write(`<h1>Hello ${sess.email} </h1><br>`);
res.end('<a href='+'/logout'+'>Logout</a>');
}
else {
res.write('<h1>Please login first.</h1>');
res.end('<a href='+'/'+'>Login</a>');
}
});
router.get('/logout',(req,res) => {
req.session.destroy((err) => {
if(err) {
return console.log(err);
}
res.redirect('/');
});
});
app.use('/', router);
app.post('/api/register',regController.register);
app.post('/api/authenticate',authController.authenticate);
console.log(authController);
app.post('/controllers/register-controller', regController.register);
app.post('/controllers/authenticate-controller', authController.authenticate);
app.listen(8000);
config.js
var mysql = require('mysql');
const localAuth = require('./controllers/timeoutcontroller');
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'password',
database : 'dbname'
});
connection.connect(function(err){
if(!err) {
console.log("Database is connected");
} else {
console.log("Error while connecting with database");
}
});
function ensureAuthenticated(req, res, next) {
if (!(req.headers && req.headers.authorization)) {
return res.status(400).json({
status: 'Please log in'
});
}
// decode the token
var header = req.headers.authorization.split(' ');
var token = header[1];
localAuth.decodeToken(token, (err, payload) => {
if (err) {
return res.status(401).json({
status: 'Token has expired'
});
} else {
return knex('users').where({id: parseInt(payload.sub)}).first()
.then((user) => {
next();
})
.catch((err) => {
res.status(500).json({
status: 'error'
});
});
}
});
}
module.exports = connection;
Here I am able to connect to the mysql database and the connection is set but I'm getting the error
TypeError: Cannot read property 'email' of undefined
If someone could explain why this happens, it'd be great.
Thanks.
This means that your variable sess is undefined. Your req.session variable does not have any value inside it. You need to check why is that happening.
Try this:
let sess = req.session;
sess.user = req.user;
req.mysess=sess.user //pass like this
router.get('/', function(req, res, next) {
let sess = req.mysess;
console.log(sess);
});

Mongo/express cannot load route (Unexpected '<' in postman)

Been trying to get user user object by id from parameters, using User.findById and cannot access this route.
Postman response: Cannot GET /users/get/ with status 404 (not found) which is wierd.
Postman JSON response:
Unexpected '<'
Been using express-promise-router but also tried with default express.Router();
Here is my code:
routes/users.js
const express = require('express');
const router = require('express-promise-router')();
const passport = require('passport');
const router1 = express.Router();
require('../passport');
const { validateBody, schemas } = require('../helpers/routeHelpers');
const UsersController = require('../controllers/users');
const passportSignIn = passport.authenticate('local', { session: false });
const passportJWT = passport.authenticate('jwt', { session: false });
router.route('/signup')
.post(validateBody(schemas.authSchema), UsersController.signUp);
router.route('/signin')
.post(validateBody(schemas.authSchema), passportSignIn, UsersController.signIn);
router.route('/get/:id')
.get(UsersController.getUser);
router.route('/secret')
.get(passportJWT, UsersController.secret);
controllers/users
module.exports = router;
const JWT = require('jsonwebtoken');
const User = require('../models/user');
const { JWT_SECRET } = require('../configuration');
const signToken = (user) => {
return JWT.sign({
iss: 'CodeWorkr',
sub: user.id,
iat: new Date().getTime(), // current time
exp: new Date().setDate(new Date().getDate() + 1) // current time + 1 day ahead
}, JWT_SECRET);
};
module.exports = {
signUp: async (req, res) => {
const { email, password } = req.value.body;
// Check if there is a user with the same email
const foundUser = await User.findOne({ 'local.email': email });
if (foundUser) {
return res.status(403).json({ error: 'Email is already in use' });
}
// Create a new user
const newUser = new User({
method: 'local',
local: {
email: email,
password: password
}
});
await newUser.save();
// Generate the token
const token = signToken(newUser);
// Respond with token
return res.status(200).json({ token });
},
signIn: async (req, res) => {
// Generate token
const token = signToken(req.user);
res.status(200).json({ token });
},
getUser: async (req, res) => {
User.findById(req.params.id)
.then((user) => {
res.status(200).json({ user });
console.log('test');
});
},
secret: async (req, res) => {
console.log('I managed to get here!');
res.json({ secret: 'resource' });
}
};
server.js
const express = require('express');
const morgan = require('morgan');
const bodyParser = require('body-parser');
const cors = require('cors');
const mongoose = require('mongoose');
const passport = require('passport');
const db = require('./configuration/config').mongoURI;
const dbTest = require('./configuration/config').mongoURITest;
mongoose.Promise = global.Promise;
if (process.env.NODE_ENV === 'test') {
mongoose.connect(dbTest, { useMongoClient: true });
} else {
mongoose.connect(db, { useMongoClient: true });
}
const app = express();
app.use(cors());
app.use(passport.initialize());
app.use(passport.session());
// Middlewares moved morgan into if for clear tests
if (!process.env.NODE_ENV === 'test') {
app.use(morgan('dev'));
}
app.use(bodyParser.json());
// Routes
app.use('/users', require('./routes/users'));
// Start the server
const port = process.env.PORT || 3001;
app.listen(port);
console.log(`Server listening at ${port}`);
Other post routes works fine,

Resources