I am new to sessions and this is my first serious coding project. I've tried a million things and I can't figure out why the session isn't persisting through different routes. When I log req.session.id from two routes, it gives me two different ids when it should be the same one.
const express = require('express');
const cors = require('cors');
const mongoose = require('mongoose');
const session = require('express-session');
const bcrypt = require('bcrypt');
let User = require('./models/user.model');
const MongoStore = require('connect-mongo')(session);
require('dotenv').config();
const app = express();
const port = process.env.PORT || 5000;
app.set('trustproxy', true);
app.use(cors(corsOptions));
app.use(cors());
app.use(express.json());
const uri = process.env.ATLAS_URI;
mongoose.connect(uri, { useNewUrlParser: true, useCreateIndex: true, useUnifiedTopology: true });
const connection = mongoose.connection;
connection.once('open', () => {
console.log("MongoDB database connection established successfully")
})
app.listen(port, () => {
console.log(`Server is running on port: ${port}`);
});
const SESS_NAME = 'session';
const SESS_SECRET = 'youshouldchangethis'
const IN_PROD = false;
app.use(session({
name: SESS_NAME,
resave: false,
store: new MongoStore({ mongooseConnection: mongoose.connection }),
saveUninitialized: true,
secret: SESS_SECRET,
proxy: true,
cookie: {
sameSite: true,
secure: IN_PROD,
}
}));
The login route creates the session (the session is stored inside Mongodb just fine at this point), then react redirects to dashboard, where req.session comes back undefined and I'm unable to access that session. Here's the login and dashboard routes. Any help is greatly appreciated!
app.post('/login', (req, res) => {
console.log("in login post");
User.findOne({ email: req.body.email })
.then(user => {
bcrypt.compare(req.body.password, user.password, function (err, result) {
if(result == true){
req.session.userId = user._id;
console.log(req.session.id);
res.send(user);
} else {
res.send('Authentication Failed');
}
})
})
.catch(err => res.send('Authentication Failed'));
});
// Dashboard Router
app.get('/dashboard', (req, res) => {
if (req.session.userId){
User.findOne({ email: req.session.user.email }) // FIX: not able to find session / user
.then(user => {
console.log("found user")
// req.session.user = user;
res.send(user);
})
.catch(err => {
//req.session.reset();
res.send(err);
})
} else {
console.log(req.session.id);
}
});
I found this in express-session docs, maybe this is what you are looking for :
Session.save(callback)
....
There are some cases where it is useful to call this method, for example, redirects, long-lived requests or in WebSockets.
req.session.save(function(err) {
// session saved
})
Related
I have an issue with persisting sessions in the DB.
I tried to store the session in MemoryStore to track the session's content, and the outupt is as expected, everything else works as expected.
But with MongoStore , the sessions collection gets createad in the DB and
everything else works as expected, but the session is not stored in the DB !!
Here is the code: ( i'm using Postman to send requests)
index.js -->
const express = require('express');
require('./db');
const passport = require('passport');
const session = require('express-session');
const cookieParser = require('cookie-parser');
const MongoStore = require('connect-mongo');
const authRouter = require('./routes/auth');
const productsRouter = require('./routes/routing');
require('./routes/passport-local');
// const memoryStore = new session.MemoryStore();
const app = express();
const PORT = 3000;
app.listen(PORT, () => console.log(`Server running on Port ${PORT}`));
app.use(express.json());
app.use(cookieParser());
app.use(
session({
secret: 'ALKSDFLKSDLFMK',
resave: false,
saveUninitialized: false,
sotre: MongoStore.create({
mongoUrl: 'mongodb://localhost/express_tuto',
}),
// store: memoryStore,
})
);
app.use(passport.initialize());
app.use(passport.session());
// app.use((req, res, next) => {
// console.log(memoryStore);
// console.log(req.user);
// next();
// });
app.use('/auth', authRouter);
app.use('/products', productsRouter);
./routes/auth.js -->
const { Router } = require('express');
const passport = require('passport');
const router = Router();
router.post(
'/login',
passport.authenticate('local'),
(req, res) => {
console.log(req.session);
console.log(req.user);
console.log(`sessionID: ${req.sessionID}`);
res.send('Logged in');
}
);
module.exports = router;
./routes/passport-local.js -->
const LocalStrategy = require('passport-local').Strategy;
const bcrypt = require('bcryptjs');
const User = require('../db/schemas/User');
const passport = require('passport');
passport.serializeUser((user, done) => {
console.log('serializing');
done(null, user.id);
});
passport.deserializeUser(async (id, done) => {
console.log('deserializing');
try {
const user = await User.findById(id);
if (user) {
done(null, user);
}
} catch (err) {
console.log(err);
done(err, null);
}
});
passport.use(
new LocalStrategy(
{ usernameField: 'email' },
async (email, password, done) => {
const user = await User.findOne({ email });
if (!user) {
console.log('no matching email!');
done(null, false);
}
try {
if (await bcrypt.compare(password, user.password)) {
console.log('user found');
done(null, user);
} else {
console.log('password incorrect');
done(null, false);
}
} catch (err) {
return done(err);
}
}
)
);
I am expecting to see the session stored in the DB given that everything ELSE works as expected!
My bad, there is a typo in the session store option.
sotre: MongoStore.create...//--> store:
I am trying to register a new user using mongoose and authenticate the user using passport but I keep getting this error password:validatorError path 'password ' is require. I cant seem to figure out how to solve this error.
I am newbie and am trying to learn authentication ,any assistance is highly appreciated.
const hbs = require("express-handlebars")
const mongoose = require("mongoose")
const session = require("express-session")
const passport = require("passport")
const passportLocalMongoose = require("passport-local-mongoose")
require("dotenv").config()
const app = express()
const PORT = process.env.PORT || "8000"
// middleware
app.engine("hbs", hbs({extname: '.hbs'}))
app.set("view engine", 'hbs')
app.use(express.static(__dirname + "/public"))
// for parsing
app.use(express.urlencoded({extended: false}))
// for testing
app.use(express.json())
// creates a session
app.use(session({
secret: "verysolidsecret",
resave: false,
saveUninitialized: false
}))
//initialize passport
app.use(passport.initialize())
//use passport to manage session
app.use(passport.session())
// conncet to local MongoDB
const url = 'mongodb://127.0.0.1:27017/authentication'
mongoose.connect(url, {
useNewUrlParser: true,
useUnifiedTopology: true
})
// log error or success message
mongoose.connection.once("open", () => {
console.log('connected to database',url)
})
mongoose.connection.on("error", err => console.log("connection", err))
// schema and model
const UserSchema = new mongoose.Schema({
username: {
type: String,
required: true
},
password: {
type: String,
required: true
}
})
// mongoose passport plugin to salt,hash and store the user into MongoDB
UserSchema.plugin(passportLocalMongoose)
// create mongoose model
const User = mongoose.model('User',UserSchema)
passport.use(User.createStrategy());
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
// setup Routes
app.get("/",(req,res) => {
res.render("index", {title:"Home"})
})
app.get("/login", (req,res) =>{
res.render("login", {title: "Login"})
})
app.get("/index", (req,res) =>{
if (req.isAuthenticated()){
res.render("index", {title: "Index"})
}
else{
res.redirect("/login")
}
})
app.get("/register", (req,res) =>{
res.render("register", {title: "Register"})
})
// register user
app.post("/register", (req,res) =>{
User.register({username:req.body.Username},req.body.password, function(err, user){
if (err) {
console.log(err)
res.redirect("/register")
}
else{
passport.authenticate("local")(req,res, function(){
res.redirect("/index")
})
}
})
})
// login a user
app.post("/login", (req,res) =>{
})
app.listen(PORT, () => {
console.log(`server is up and running on PORT: ${PORT}`)
})```
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.
Currently a user can sign in with github, and i can see it gets the req.user in the callback function, and on passport github file
console.log(`frontid ${req.user.id}`) // logs user id
and passport
console.log(`backbro ${id}`); // logs an id
however, when i go on this route, the github user returns null and im not sure why. There were a few times, i see the signed in github user return in the current_user route, however its rare that i see it now. It sometimes shows, sometimes dont. Kinda wierd. Could it be a session issue ?
router.get("/current_user", (req, res) => {
if(req.user){
res.status(200).send({ user: req.user});
} else {
res.json({ user:null})
}
});
yes i looked at the following links, still no suitable answer.
Node + Express + Passport: req.user Undefined
req.user undefined after twitter authentication using express sever, passport.js
The way im accessing this link, is by explictily calling
localhost:8000/api/users/auth/github
in the address bar.
routes/users
router.get('/auth/github', passport.authenticate('github', {
scope:[ 'profile', 'id']
}));
router.get('/auth/github/callback',
passport.authenticate('github', { session:true, failureRedirect: 'http:localhost:8001/signIn' }),
function(req, res) {
// Successful authentication, redirect home.
// var token = jwt.sign({ id: req.user.id}, process.env.JWT_SECRET );
// // res.cookie("jwt", token, { expires: new Date(Date.now() + 10*1000*60*60*24)});
// jwt.verify(token, process.env.JWT_SECRET, function(err, data){
// console.log(err, data);
// })
const user = req.user
req.logIn(user, err => {
models.User.findOne({
where: {
id: req.user.id,
},
}).then(user => {
const token = jwt.sign({ id: user.id }, process.env.JWT_SECRET);
// res.cookie("jwt", token, { expires: new Date(Date.now() + 10*1000*60*60*24)});
jwt.verify(token, process.env.JWT_SECRET, function(err, data){
console.log(err, data);
})
res.redirect('http://localhost:8001');
// console.log(req.user)
});
});
console.log(`frontid ${req.user.id}`)
// res.redirect('')
// console.log('this works', token);
});
passport-github.js
const GitHubStrategy = require('passport-github2').Strategy;
const Sequelize = require('sequelize');
const Op = Sequelize.Op;
const models = require("../models/");
// passport.serializeUser((user, done) => {
// // push to session
// done(null, user.id);
// console.log(user.id)
// });
// passport.deserializeUser((id, done) => {
// models.User.findOne({
// where: {
// id,
// },
// }).then(user => done(null, user))
// .catch(done);
// });
module.exports = async (passport) => {
passport.use(
new GitHubStrategy(
{
clientID: process.env.clientID,
clientSecret: process.env.secret,
callbackURL: 'http://127.0.0.1:8000/api/users/auth/github/callback',
passReqToCallback: true,
profileFields: ['id', 'login']
},
(req, accessToken, refreshToken, profile, done) => {
const { id, login, email} = profile._json;
console.log(`backbro ${id}`);
// console.log(req)
models.User.findOne({
where:{
id: id
}
}).then( user => {
// if user is found
if(user){
return done(null, user)
}
// else create new user
else{
models.User.create({
id: id,
username:login,
email: email,
createdAt: Date.now()
}).then( user => {
console.log('github user created');
return done(null, user);
})
}
})
}
)
);
passport.serializeUser((user, done) => {
// push to session
return done(null, user.id);
});
passport.deserializeUser((userId, done) => {
// console.log('calling deserial' + userId);
// // TODO: findByPk syntax? findById deprecated? Try later after sucessfully record data in DB
models.User
.findOne({ where: { id: userId } })
.then(function(user){
// console.log(user);
return done(null, userId);
}).catch(function(err){
done(err, null);
});
// return done(null, id);
});
}
app.js
const express = require('express');
const app = express();
const userRoute = require('./routes/users');
const postRoute = require('./routes/posts');
const bodyParser = require('body-parser');
const logger = require('morgan');
const session = require('express-session');
const cookieParser = require('cookie-parser') ;
const dotenv = require('dotenv');
const env = dotenv.config();
const cors = require('cors');
const models = require('./models/');
const host = '0.0.0.0';
const PORT = process.env.PORT || 8000;
const passport = require('passport');
const path = require('path');
const Sequelize = require('sequelize');
const SequelizeStore = require('connect-session-sequelize')(session.Store);
const proxy = require('express-http-proxy');
app.use(function(req, res, next) {
res.locals.user = req.user; // This is the important line
// req.session.user = user
console.log(res.locals.user);
next();
});
app.use(cors({
origin: process.env.ALLOW_ORIGIN,
credentials: false,
allowedHeaders: 'X-Requested-With, Content-Type, Authorization',
methods: 'GET, POST, PATCH, PUT, POST, DELETE, OPTIONS',
exposedHeaders: ['Content-Length', 'X-Foo', 'X-Bar'],
}))
var sequelize = new Sequelize(
process.env.POSTGRES_DB,
process.env.POSTGRES_USER,
process.env.POSTGRES_PASSWORD,{
"dialect": "sqlite",
"storage": "./session.sqlite"
});
myStore = new SequelizeStore({
db:sequelize,
})
if (!process.env.PORT) {
require('dotenv').config()
}
// console.log(process.env.DATABASE_URL);
if (!process.env.PORT) {
console.log('[api][port] 8000 set as default')
console.log('[api][header] Access-Control-Allow-Origin: * set as default')
} else {
console.log('[api][node] Loaded ENV vars from .env file')
console.log(`[api][port] ${process.env.PORT}`)
console.log(`[api][header] Access-Control-Allow-Origin: ${process.env.ALLOW_ORIGIN}`)
}
app.use(logger('dev'));
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'build')));
// We need a store in order to save sessions, instead of the sessions clearing out on us :)
require('./config/passport')(passport); // PASSPORT Init
require('./config/passport-github')(passport); // PASSPORT Init
app.use(cookieParser());
app.use(bodyParser.json());
app.use(session({
store: myStore,
saveUninitialized: false,
resave:false,
cookie: { maxAge: 30 * 24 * 60 * 60 * 1000 }, // 30 days
secret : process.env.JWT_SECRET,
}));
myStore.sync();
app.use(passport.initialize());
app.use(passport.session());
app.use(bodyParser.urlencoded({ extended:false}));
// this code may be useless or useful, still trying to understand cors.
app.use('/api/users', userRoute );
app.use('/api/posts', postRoute );
// In order to use REACT + EXPRESS we need the following code, alone with a build
// in the client folder we run a npm run build in the client folder then it is referred
// in the following code.
app.use(express.static(path.join(__dirname, 'client/build')));
if(process.env.NODE_ENV === 'production') {
app.use(express.static(path.join(__dirname, 'client/build')));
//
app.get('*', (req, res) => {
res.sendfile(path.join(__dirname = 'client/build/index.html'));
})
}
//build mode
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname+'/client/public/index.html'));
})
models.sequelize.sync().then(function() {
app.listen(PORT, host, () => {
console.log('[api][listen] http://localhost:' + PORT)
})
})
I have some problems with the express session where I cannot retrieve my session variable that I had stored previously. Below are parts of my codes that I had written.
server.js
let express = require('express'),
path = require('path'),
bodyParser = require('body-parser'),
cors = require('cors'),
config = require('./config/database'),
expressSession = require('express-session'),
uid = require('uid-safe'),
db;
let app = express();
//Import Routes
let auth = require('./routes/auth'),
chimerListing = require('./routes/chimer-listing'),
brandListing = require('./routes/brand-listing');
//Specifies the port number
let port = process.env.PORT || 3000;
// let port = 3000;
// Express session
app.use(expressSession({
secret: "asdasd",
resave: true,
saveUninitialized: false,
cookie: {
maxAge: 36000000,
secure: false
}
}));
//CORS Middleware
app.use(cors());
//Set Static Folder
var distDir = __dirname + "/dist/";
app.use(express.static(distDir));
//Body Parser Middleware
app.use(bodyParser.json());
//MongoDB
let MongoClient = require('mongodb').MongoClient;
MongoClient.connect(config.database, (err, database) => {
if (err) return console.log(err)
db = database;
//Start the server only the connection to database is successful
app.listen(port, () => {
console.log('Server started on port' + port);
});
});
//Make db accessbile to routers;
app.use(function(req, res, next) {
req.db = db;
res.set('Access-Control-Allow-Origin', '*');
res.set('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.set('Access-Control-Allow-Headers', 'Content-Type');
next();
});
//Routes
app.use('/login', auth);
app.use('/user-listing', userListing);
app.use('/brand-listing', brandListing);
//Index Route
app.get('/', (req, res) => {
res.send('Invalid Endpoint');
});
genuuid = function() {
return uid.sync(18);
};
auth.js
let express = require('express'),
router = express.Router(),
db;
//Login Router for chimer
router.post('/chimer', (req, res, next) => {
db = req.db;
// let client = req.client;
db.collection('chimeUser').find({
Username: req.body.username,
Password: req.body.password
}).toArray().then(function(docs) {
//If there is such user
if (docs.length >= 1) {
req.session.chimerId = docs[0]._id;
console.log(req.session);
req.session.save(function(err) {
// session saved
if (err)
console.log(err)
res.json({
success: true,
chimerId: docs[0]._id
//objects: docs
});
})
} else {
res.json({
success: false,
//objects: docs
})
}
});
});
//Login Router brand
router.post('/brand', (req, res, next) => {
db = req.db;
db.collection('brand').find({
Username: req.body.username,
Password: req.body.password
}).toArray().then(function(docs) {
req.session.brand = docs;
console.log(req.session.brand);
//If there is such user
if (docs.length >= 1) {
res.json({
success: true,
//objects: docs
})
} else {
res.json({
success: false,
//objects: docs
})
}
//db.close()
});
});
});
module.exports = router;
user-listing.js
let express = require('express'),
moment = require('moment'),
router = express.Router(),
// ObjectID = require('mongodb').ObjectID,
db, client;
// let applyListing = require('../models/chimer-listing');
//Retrieve All Listing
router.get('/getAllListing', (req, res, next) => {
db = req.db;
console.log(req.session)
db.collection('listing').find().toArray().then(function(listing) {
//If there is any listing
if (listing.length >= 1) {
res.json({
success: true,
results: listing
})
} else {
res.json({
success: false,
})
}
//db.close()
});
});
module.exports = router;
So in my server.js, I have three routes file which is auth, user-listing, and brand-listing.
Firstly, a user will need to login with the web application which is developed in angular2 and this will trigger the auth route. It will then check for the credentials whether does it exist in the database if it exists I will then assign an ID to req.session.chimerId so that in other routes I will be able to use this chimerId.
Next, after the user has logged in, they will then retrieve an item listing. The problem arises where I can't seem to retrieve the req.session.chimerId that I had previously saved. It will be undefined
NOTE: I tried this using Postman and the browser. In the Postman it works, I am able to retrieve back the req.session.chimerId whereas when I use the angular2 application to hit the endpoints req.session.chimerId is always null