Express-session does not create any session - mongodb

Im trying to implement some basic sessions functionality in my toy project with express-session and connect-mongo for session storage.
What i expect:
Browser gets cookie after recieving response from server
Session data is written to collection "sessions"
I get debug messages from express-session in console, because i start the app with DEBUG=express-session:* nodemon ./bin/www
What i get instead:
Browser never gets cookie
No documents are being created in the collection (the collection itself is being created every time i launch the app though)
There are no debug messages from express-session in the console
Everything related to DB and session setups in the app.js file:
// DB setup
var mongoDB = require('./k'); // K is a file containing connection string
mongoose.connect(mongoDB, {
useNewUrlParser: true,
useUnifiedTopology: true
})
var db = mongoose.connection
db.on('error', console.error.bind(console, 'MongoDB connection Error: '))
// Session setup
const connection = mongoose.createConnection(mongoDB, {
useNewUrlParser: true,
useUnifiedTopology: true
})
const sessionStore = new MongoStore({
mongooseConnection: connection,
collection: 'sessions'
})
app.use(session({
secret: 'some secret',
resave: false,
saveUninitialized: true,
store: sessionStore,
cookie: {
maxAge: 1000 * 60 * 60 * 24
}
}));
Is there anything i clould be missing? What could be causing this issue for me?

Try:
var MongoStore = require('connect-mongostore')(session);
app.use(session({
secret: 'my secret',
store: new MongoStore({'db': 'sessions'})
}));

Looks like the problem was being caused by the order of middleware in my app.js file. I moved the code with DB setup and session setup right above routers and it worked. app.js before:
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var entriesRouter = require('./routes/entries')
const categoriesRouter = require('./routes/categories')
const session = require('express-session');
const MongoStore = require('connect-mongo')(session)
const mongoose = require('mongoose')
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({
extended: false
}));
// app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/entries', entriesRouter)
app.use('/categories', categoriesRouter)
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
// DB setup
var mongoDB = require('./k'); // K is a file containing connection string
mongoose.connect(mongoDB, {
useNewUrlParser: true,
useUnifiedTopology: true
})
var db = mongoose.connection
db.on('error', console.error.bind(console, 'MongoDB connection Error: '))
// Session setup
const connection = mongoose.createConnection(mongoDB, {
useNewUrlParser: true,
useUnifiedTopology: true
})
const sessionStore = new MongoStore({
mongooseConnection: connection,
collection: 'sessions'
})
app.use(session({
secret: 'some secret',
resave: false,
saveUninitialized: true,
store: sessionStore,
cookie: {
maxAge: 1000 * 60 * 60 * 24,
secure: false
}
}));
module.exports = app;
app.js after:
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var entriesRouter = require('./routes/entries')
const categoriesRouter = require('./routes/categories')
const session = require('express-session');
const MongoStore = require('connect-mongo')(session)
const mongoose = require('mongoose')
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({
extended: false
}));
// app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// DB setup
var mongoDB = require('./k'); // K is a file containing connection string
mongoose.connect(mongoDB, {
useNewUrlParser: true,
useUnifiedTopology: true
})
var db = mongoose.connection
db.on('error', console.error.bind(console, 'MongoDB connection Error: '))
// Session setup
const connection = mongoose.createConnection(mongoDB, {
useNewUrlParser: true,
useUnifiedTopology: true
})
const sessionStore = new MongoStore({
mongooseConnection: connection,
collection: 'sessions'
})
app.use(session({
secret: 'some secret',
resave: false,
saveUninitialized: true,
store: sessionStore,
cookie: {
maxAge: 1000 * 60 * 60 * 24,
secure: false
}
}));
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/entries', entriesRouter)
app.use('/categories', categoriesRouter)
// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404));
});
// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;

Related

Create mongoDB Session with Socket.io connection only

I need to create a session on MongoDB when the socket connection start, I have the following code:
var express = require('express');
var session = require('express-session');
var sharedsession = require("express-socket.io-session");
var MongoDBStore = require('connect-mongodb-session')(session);
var app = express();
var http = require('http').createServer(app);
var io = require('socket.io')(http);
var store = new MongoDBStore({
uri: 'CONNECTION TO MONGODB',
collection: 'sessions',
connectionOptions: {
useNewUrlParser: true
}
});
// Catch errors
store.on('error', function(error) {
console.log(error);
});
let sessionConfig = require('express-session')({
secret: 'This is a secret',
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 7 // 1 week
},
store: store,
httpOnly: false,
resave: true,
saveUninitialized: true
});
app.use(sessionConfig);
io.use(sharedsession(sessionConfig, {
autoSave:true
}));
app.get('/', function(req, res) {
res.send('<html><head><script src="http://localhost:3001/socket.io/socket.io.js"></script><script>var socket = io();</script></head><body>Test</body></html>');
});
io.on('connection', (socket) => {
console.log('a user connected');
console.log('socket.handshake',socket.handshake.session);
console.log(socket.handshake.xdomain);
console.log("A USER LOGGED IN WITH ID: ", socket.request.user);
// Accept a login event with user's data
socket.on("login", function(userdata) {
socket.handshake.session.userdata = userdata;
socket.handshake.session.save();
});
socket.on("logout", function(userdata) {
if (socket.handshake.session.userdata) {
delete socket.handshake.session.userdata;
socket.handshake.session.save();
}
});
});
http.listen(3001, () => {
console.log('listening on *:3000');
});
server = app.listen(3000);
If I access to , the session is created successfully in MongoDB, I understand that the configuration with express is ok, and the Socket Share that session correctly when I try to connect from the same domain.
The problem is, that I have a mobile app with ionic v4, that only access from a socket connection and the session is never created on MongoDB.
Any thoughts?
UPDATE 1:
I try to add passport.socketio to get a proper way to add authentication to my app, and the output of this code, is Not Session found, its right, the socket connection never add the session to the MongoDB:
var express = require('express');
var session = require('express-session');
var sharedsession = require("express-socket.io-session");
let passport = require('passport');
let passportSocketIo = require("passport.socketio");
let cors = require('cors')
var MongoDBStore = require('connect-mongodb-session')(session);
var app = express();
var http = require('http').createServer(app);
var io = require('socket.io')(http);
var store = new MongoDBStore({
uri: 'MONGO DB STRING CONNECTION',
collection: 'sessions',
connectionOptions: {
useNewUrlParser: true
}
});
// Catch errors
store.on('error', function(error) {
console.log(error);
});
app.use(cors());
app.use(passport.initialize());
app.use(passport.session());
let config = {
passport : passport,
secret: 'This is a secret',
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 7 // 1 week
},
store: store,
httpOnly: false,
resave: true,
saveUninitialized: true,
success: onAuthorizeSuccess, // *optional* callback on success - read more below
fail: onAuthorizeFail
};
let sessionConfig = require('express-session')(config);
app.use(sessionConfig);
io.origins('*:*');
io.use(sharedsession(sessionConfig, passportSocketIo.authorize(config)));
app.get('/', function(req, res) {
res.send('<html><head><script src="http://localhost:3001/socket.io/socket.io.js"></script><script>var socket = io();</script></head><body>Test</body></html>');
});
io.on('connection', (socket) => {
console.log('a user connected');
console.log('socket.handshake',socket.handshake.session);
console.log(socket.handshake.xdomain);
console.log("A USER LOGGED IN WITH ID: ", socket.request.user);
// Accept a login event with user's data
socket.on("login", function(userdata) {
socket.handshake.session.userdata = userdata;
socket.handshake.session.save();
});
socket.on("logout", function(userdata) {
if (socket.handshake.session.userdata) {
delete socket.handshake.session.userdata;
socket.handshake.session.save();
}
});
});
http.listen(3001, () => {
console.log('listening on *:3000');
});
server = app.listen(3000);
function onAuthorizeSuccess(data, accept){
console.log('successful connection to socket.io');
// accept(); //Let the user through
}
function onAuthorizeFail(data, message, error, accept){
console.log("Errror",error);
if(error) accept(new Error(message));
console.log('failed connection to socket.io:', message);
// accept(null, false);
}
Try
//Before io.on('connection....
io​.​engine​.​generateId​ ​=​ (​req​) ​=>​ {
//Try to get the cookie out from
//req.rawHeaders and return it
//so the socket ID will equal to the session Id
});
//The connection event
​io​.​on​(​'​connection​'​, ​socket​ ​=>​ { ....
//You can then do a mongoose search query using the socket Id here to match the user in the db

Knex Postgres Heroku - Error: Unable to Acquire Connection

I'm aware of the post and similar question here(Knex Migration Postgres Heroku - Error: Unable to Acquire Connection) I'm not sure what is missing in my .env I just basically have the following line in there : HOST= http://localhost:3000.
My knexfile:
module.exports = {
development: {
client: 'pg',
connection: 'postgres://localhost/eka_dev',
migrations: {
tableName: 'knex_migrations'
}
},
test: {
client: 'pg',
connection: 'postgres://localhost/eka_test',
migrations: {
tableName: 'knex_migrations'
}
},
production: {
client: 'pg',
connection: process.env.DATABASE_URL,
migrations: {
tableName: 'knex_migrations'
}
}
};
Knex file:
const environment = process.env.NODE_ENV || 'development';
const knexConfig = require('./knexfile')[environment];
const knex = require('knex')(knexConfig);
module.exports = knex;
app.js file:
const express= require('express');
const PORT = process.env.PORT || 3000;
const app = express();
const bodyParser = require('body-parser');
const path = require('path');
const cors = require('cors');
const usersRoute = require('./routes/users');
if (process.env.NODE_ENV !== 'production') {
require('dotenv').config();
}
const allowCrossDomain = function (req, res, next) {
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept');
if (req.method == 'OPTIONS') {
res.send(200);
} else {
next();
}
};
app.use(allowCrossDomain);
app.use(cors());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'build')));
app.use('/api', usersRoute);
app.listen(PORT, () => {
console.log(`Express server listening on port ${PORT}`);
});
module.exports = app;
You need to define NODE_ENV=production environment variable in your Heroku setup and check what is the contents of DATABASE_URLvariable.

node js and passport validation miss passport session

I have app.js as below
var express = require('express'),
path = require('path'),
favicon = require('serve-favicon'),
logger = require('morgan'),
cookieParser = require('cookie-parser'),
bodyparser = require('body-parser'),
db = require('./model/db');
var app=express();
var dbConfig = require('./db.js');
var mongoose = require('mongoose');
mongoose.Promise = global.Promise;
mongoose.createConnection(dbConfig.url);
var passport = require('passport');
app.use(bodyparser.urlencoded({
extended:true
}));
var expressSession = require('express-session');
var flash = require('connect-flash');
app.use(expressSession({
secret: 'crackalackin',
resave: true,
saveUninitialized: true,
cookie : { secure : false, maxAge : (4 * 60 * 60 * 1000) }, // 4 hours
}));
app.use(passport.initialize());
app.use(passport.session());
// Using the flash middleware provided by connect-flash to store messages in session
// and displaying in templates
var flash = require('connect-flash');
app.use(flash());
// Initialize Passport
var initPassport = require('./passport/init');
initPassport(passport);
var routes = require('./routes/index')(passport);
app.use('/', routes);
/// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
app.listen(6061,function(){
console.log("started on port 6061");
});
/passport/init.js
var login = require('./login');
var signup = require('./signup');
var User = require('../models/user');
module.exports = function (passport) {
// Passport needs to be able to serialize and deserialize users to support persistent login sessions
passport.serializeUser(function (user, done) {
done(null, user._id);
});
passport.deserializeUser(function (id, done) {
try {
User.getById(id, function (err, user) {
done(err, user);
});
} catch (ex) {
}
});
// Setting up Passport Strategies for Login and SignUp/Registration
login(passport);
signup(passport);
}
when I write console.log(req.session) in /passport/login.js at validation function.
I get output like
Session {
cookie:
{ path: '/',
_expires: 2017-02-01T14:10:38.523Z,
originalMaxAge: 14400000,
httpOnly: true,
secure: false } }
I miss the
passport: {}
so I can login but can not generate passport session.
So isAuthenticated function say "login plase".
how can I manage session here.

API that fetches all records from mongoDB using express and mongoskin driver

I am beginner in Mean stack I am developing an API that fetches all records from mongodb using express. But I am not able to fetch all records from the database. I can't figure what I am doing wrong, I am doing it as follows:
This is my main app (server.js)
require('rootpath')();
var express = require('express');
var app = express();
var session = require('express-session');
var bodyParser = require('body-parser');
var expressJwt = require('express-jwt');
var config = require('config.json');
app.set('view engine', 'ejs');
app.set('views', __dirname + '/views');
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(bodyParser.json());
app.use(session({
secret: config.secret,
resave: false,
saveUninitialized: true
}));
// use JWT auth to secure the api
app.use('/api', expressJwt({
secret: config.secret
}).unless({
path: ['/api/users/authenticate', '/api/users/register']
}));
// routes
app.use('/', require('./controllers/login.controller'));
app.use('/register', require('./controllers/register.controller'));
app.use('/app', require('./controllers/app.controller'));
app.use('/api/users', require('./controllers/api/users.controller'));
/*// make '/app' default route
app.get('/', function (req, res) {
return res.redirect('/app');
});*/
// start server
var server = app.listen(3000, function() {
console.log('Server listening at http://' + server.address().address + ':' + server.address().port);
});
This is my user.controller.js user will make a request to the api
http://localhost:3000/api/users/userList
var express = require('express');
var router = express.Router();
var userService = require('services/user.service');
router.get('/userList', getUserList);
module.exports = router;
function getUserList(req, res) {
userService.userList()
.then(function(users) {
if (users) {
res.send(users);
} else {
res.sendStatus(404);
}
})
.catch(function(err) {
res.status(400).send(err);
});
}
This is my user.service.js where I am querying the database to fetch all records using mongoskin driver.
var Q = require('q');
var mongo = require('mongoskin');
var db = mongo.db("mongodb://localhost:27017/EmployeeForm", {
native_parser: true
});
db.bind('users');
var service = {};
service.userList = userList;
module.exports = service;
function userList() {
var deferred = q.defer();
db.users.find(function(err, users) {
if (err) deferred.reject(err.name + ': ' + err.message);
});
return deferred.promise;
}
So i think it's find issue.
MongoDB find method return cursor by default.
https://docs.mongodb.com/manual/reference/method/db.collection.find/
From https://github.com/kissjs/node-mongoskin they use method toArray which will transform cursor into array of objects like this
db.find.toArray(callback)
So try like this in userList()
function userList() {
var deferred = q.defer();
db.users.find({}).toArray(function(err,docs){
err ? deferred.reject(err) : deferred.resolve(docs);
});
return deferred.promise;
}
Hope this helps.

Nodejs/Express Session - Error: Can't set headers after they are sent

I am getting the below error while trying to use express session with a simple nodejs sample app.
When "resave" is set to true the below error appears, however when the same is set to false, there is no error.
GET / 304 13.380 ms - - Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:344:11)
at ServerResponse.header
(/Volumes/SURESH/GSKLabs/NodeApp/node_modules/express/lib/response.js:718:10)
at ServerResponse.contentType
(/Volumes/SURESH/GSKLabs/NodeApp/node_modules/express/lib/response.js:551:15)
at ServerResponse.send
(/Volumes/SURESH/GSKLabs/NodeApp/node_modules/express/lib/response.js:138:14)
at done
(/Volumes/SURESH/GSKLabs/NodeApp/node_modules/express/lib/response.js:957:10)
Below is the code app.js
var express = require('express');
var session = require('express-session');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var mongojs = require('mongojs');
var mongoStore = require('connect-mongo')(session);
var db = mongojs('mongodb://localhost:27017/checker', ['sessions']);
var routes = require('./routes/index');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
var sessionStore = new mongoStore({
db: db,
})
// Session details
app.use(session({
secret: 'check first',
name: {secure: true, maxAge: 60000},
store: sessionStore, // connect-mongo session store
proxy: true,
resave: true,
saveUninitialized: true
}));
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace/Volumes/SURESH/GSKLabs/NodeApp/node_modules/express/lib/router/index.js:310:13
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
routes/index.js
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
package.json
{
"name": "NodeApp",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node ./bin/www"
},
"dependencies": {
"body-parser": "~1.15.1",
"connect-mongo": "^1.3.2",
"cookie-parser": "~1.4.3",
"debug": "~2.2.0",
"ejs": "~2.4.1",
"express": "~4.13.4",
"express-session": "^1.14.1",
"mongojs": "^2.4.0",
"morgan": "~1.7.0",
"serve-favicon": "~2.3.0"
}
}
As per my understanding, since the resave:true, express session trying to set the cookie after the response is already sent. Cannot change to resave:false, as it needs to be "true" for using rolling option in express session.
Any help how to solve this error in the above sample code. Thanks.