How to set up mongoose and connect-mongo? - node.js

I had an Error setting TTL error when starting my application in express. Maybe the problem is because I use for sessions and for db operations the same database through different connections.
So it there a specific sequence of requiring connect-mongo and mongoose that needs to be respected if I want to store my sessions in mongodb via the connect-mongo middleware and use mongo as my database for my app specific data?
Currently my app looks like this:
App.app.use(express.session({
store: new MongoStore({
db: settings.cookie.db,
host: settings.cookie.host,
port: settings.cookie.port
}),
secret: settings.cookie.secret
}))
and later I set start the connection for mongo:
function connect(connectionString) {
mongoose.connect(connectionString)
var db = mongoose.connection
db.on('error', console.error.bind(console, 'connection error'))
db.once('open', function callbck() {
console.log('Mongoose connected at: ', connectionString)
})
}
There are no error logs apart
Also how do I tear down properly mongo connections when I close my app (from command line let's say)? For this question I found the answer here I think.

First of all i've created a sessionStore module
var mongoose = require('mongoose'),
express = require('express'),
MongoStore = require('connect-mongo')(express),
sessionStore = new MongoStore({mongoose_connection: mongoose.connection});
module.exports = sessionStore;
Then i've included it into app
sessionStore = require('libs/sessionStore');
And finaly
app.use(express.session({
secret: config.get('session:secret'),
key: config.get('session:key'),
cookie: config.get('session:cookie'),
store: sessionStore
}));
That's config
"session": {
"secret": "secret",
"key": "connect.sid",
"cookie": {
"path": "/",
"httpOnly": true,
"maxAge": null
}
},

Related

Express session won't persist, even with MongoStore using connect-mongo

When I restart my server, my session ends and I am logged out. This does not happen on a regular page refresh. I am using connect-mongo to remedy this:
var session = require('express-session');
const MongoStore = require('connect-mongo')(session);
Here is the code I am using to store my session, reusing an existing Mongo connection called thisDb:
app.use(session({
secret: secretHash,
saveUninitialized: true,
resave: true,
secure: false,
store: new MongoStore({ db: thisDb })
}));
During a successful log in:
var day = 60000*60*24;
req.session.expires = new Date(Date.now() + (30*day));
req.session.cookie.maxAge = (30*day);
In my Mongo shell, I can verify that a new session is created when I log in:
db.sessions.find()
{"cookie":{"originalMaxAge":2592000000,"expires":"2017-11-17T20:36:12.777Z","httpOnly":true,"path":"/"},"user":{"newNotifications":false,"username":"max","admin":"true","moderator":"true"},"expires":"2017-11-17T20:36:10.556Z"}
Well, almost 3 years later i was having this issue. Don't know if OP was using Passport but i resolved this issue by moving this functions from inside the passport.use function to outside:
passport.serializeUser(function(user, done){
done(null,user.id);
});
passport.deserializeUser((id,done) => {
User.findById(id, (err,user) => {
done(null,user);
});
});

Instance of connect-mongo module do nothing

Hie. I've a problem. I use windows and my app is a nodejs app. I store sessions in mongodb and use connect-mongo module. And this is my problem:
var session = require('express-session');
var MongoStore = require('connect-mongo')(session);
var sessionStore = new MongoStore({ url: 'mongodb://localhost/latte', db: 'latte' }, function(err) {
console.log(arguments);
// ... some code use sessionStore variable ...
var server = http.createServer(app);
server.listen('80', 'latte.ru', function(){
log.info('Express server listening on port 80');
});
});
When I create an instance of MongoStore callback doesn't fire and console.log doesn't fire too, but I have no errors in console.
When I run server without of MongoStore all is OK.
In windows console mongo works fine.
Please help to resolve this problem.
Try with this,
var sessionStore = new MongoStore({ host: 'localhost', port: 27017, db: 'test-app'}, function(err){
console.log(arguments)
});
Your MongoStore url doesn't appear to be in sync.

How to save and retrieve session from Redis

I am trying to integrate Redis sessions into my authentication system written in Node.js.
I have been able to successfully set up Redis server, connect-redis and Express server.
Here is my setup (just the important bit):
var express = require("express");
var RedisStore = require("connect-redis")(express);
var redis = require("redis").createClient();
app.use(express.cookieParser());
app.use(express.session({
secret: "thisismysecretkey",
store: new RedisStore({ host: 'localhost', port: 6379, client: redis })
}));
Now... How do I actually create, read and destroy the session? I am aware that that is probably extremely simple. I have read tons of articles on how to setup connect-redis and many questions here on SO, but I swear each one stops on just the configuration and does not explain how to actually use it...
That should be all there is to it. You access the session in your route handlers via req.session. The sessions are created, saved, and destroyed automatically.
If you need to manually create a new session for a user, call req.session.regenerate().
If you need to save it manually, you can call req.session.save().
If you need to destroy it manually, you can call req.session.destroy().
See the Connect documentation for the full list of methods and properties.
Consider this code.
var express = require('express');
var redis = require("redis");
var session = require('express-session');
var redisStore = require('connect-redis')(session);
var bodyParser = require('body-parser');
var client = redis.createClient();
var app = express();
app.set('views', __dirname + '/views');
app.engine('html', require('ejs').renderFile);
app.use(session({
secret: 'ssshhhhh',
// create new redis store.
store: new redisStore({ host: 'localhost', port: 6379, client: client,ttl : 260}),
saveUninitialized: false,
resave: false
}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.get('/',function(req,res){
// create new session object.
if(req.session.key) {
// if email key is sent redirect.
res.redirect('/admin');
} else {
// else go to home page.
res.render('index.html');
}
});
app.post('/login',function(req,res){
// when user login set the key to redis.
req.session.key=req.body.email;
res.end('done');
});
app.get('/logout',function(req,res){
req.session.destroy(function(err){
if(err){
console.log(err);
} else {
res.redirect('/');
}
});
});
app.listen(3000,function(){
console.log("App Started on PORT 3000");
});
So you need to install connect-redis and pass your express-session instance to it.
Then in middleware initialize redisStore with server details like this.
app.use(session({
secret: 'ssshhhhh',
// create new redis store.
store: new redisStore({ host: 'localhost', port: 6379, client: client,ttl : 260}),
saveUninitialized: false,
resave: false
}));
I put ttl to 260, you can increase. After TTL reaches its limits, it will automatically delete the redis key.
In routers you can use req.session variable to SET, EDIT or DESTROY the session.
One more thing...
If you want custom cookie i.e not as same as in your Redis store you can use cookie-parser to set cookie secrets.
Hope it helps.
link : https://codeforgeek.com/2015/07/using-redis-to-handle-session-in-node-js/
You can also use the Redis monitor tool to see all the action in real time! When you refresh your app you will see the data appear in the console window.
redis-cli monitor
Sample Output for Sessions using tj/connect-redis
1538704759.924701 [0 unix:/tmp/redis.sock] "expire" "sess:F9x-YgbgXu1g7RG8tFlkwY3RV0JzHgCh" "3600"
1538704759.131285 [0 unix:/tmp/redis.sock] "get" "sess:F9x-YgbgXu1g7RG8tFlkwY3RV0JzHgCh"
1538704787.179318 [0 unix:/tmp/redis.sock] "set" "sess:Hl3LPbOBdKO44SG4zQHFn2gfdiWTwzWW" "{\"cookie\":{\"originalMaxAge\":3600000,\"expires\":\"2018-10-05T02:59:47.178Z\",\"secure\":true,\"httpOnly\":true,\"domain\":\".indospace.io\",\"path\":\"/\"},\"path\":\"/\",\"userAgent\":{\"family\":\"NewRelicPingerBot\",\"major\":\"1\",\"minor\":\"0\",\"patch\":\"0\",\"device\":{\"family\":\"Other\",\"major\":\"0\",\"minor\":\"0\",\"patch\":\"0\"},\"os\":{\"family\":\"Other\",\"major\":\"0\",\"minor\":\"0\",\"patch\":\"0\"}},\"ip\":\"184.73.237.85\",\"page_not_found_count\":0,\"city\":\"Ashburn\",\"state\":\"VA\",\"city_state\":\"Ashburn, VA\",\"zip\":\"20149\",\"latitude\":39.0481,\"longitude\":-77.4728,\"country\":\"US\"}" "EX" "3599"
1538704787.179318 [0 unix:/tmp/redis.sock] "set" "sess:Hl3LPbOBdKO44SG4zQHFn2gfdiWTwzWW" "{\"cookie\":{\"originalMaxAge\":3600000,\"expires\":\"2018-10-05T02:59:47.178Z\",\"secure\":true,\"httpOnly\":true,\"domain\":\".indospace.io\",\"path\":\"/\"},\"path\":\"/\",\"userAgent\":{\"family\":\"NewRelicPingerBot\",\"major\":\"1\",\"minor\":\"0\",\"patch\":\"0\",\"device\":{\"family\":\"Other\",\"major\":\"0\",\"minor\":\"0\",\"patch\":\"0\"},\"os\":{\"family\":\"Other\",\"major\":\"0\",\"minor\":\"0\",\"patch\":\"0\"}},\"ip\":\"184.73.237.85\",\"page_not_found_count\":0,\"city\":\"Ashburn\",\"state\":\"VA\",\"city_state\":\"Ashburn, VA\",\"zip\":\"20149\",\"latitude\":39.0481,\"longitude\":-77.4728,\"country\":\"US\"}" "EX" "3599"

Node.js + express.js + passport.js : stay authenticated between server restart

I use passport.js to handle auth on my nodejs + express.js application. I setup a LocalStrategy to take users from mongodb
My problems is that users have to re-authenticate when I restart my node server. This is a problem as I am actively developing it and don't wan't to login at every restart... (+ I use node supervisor)
Here is my app setup :
app.configure(function(){
app.use('/static', express.static(__dirname + '/static'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser());
app.use(express.session({secret:'something'}));
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
});
And session serializing setup :
passport.serializeUser(function(user, done) {
done(null, user.email);
});
passport.deserializeUser(function(email, done) {
User.findOne({email:email}, function(err, user) {
done(err, user);
});
});
I tried the solution given on a blog (removed the link as it does not exist any more) using connect-mongodb without success
app.use(express.session({
secret:'something else',
cookie: {maxAge: 60000 * 60 * 24 * 30}, // 30 days
store: MongoDBStore({
db: mongoose.connection.db
})
}));
EDIT additional problem : only one connection should be made (use of one connexion limited mongohq free service)
EDIT 2 solution (as an edition as I my reputation is to low to answer my question by now
Here is the solution I finally found, using mongoose initiated connection
app.use(express.session({
secret:'awesome unicorns',
maxAge: new Date(Date.now() + 3600000),
store: new MongoStore(
{db:mongoose.connection.db},
function(err){
console.log(err || 'connect-mongodb setup ok');
})
}));
There's an opensource called connect-mongo that does exactly what you need - persists the session data in mongodb
usage example (with a reuse of mongoose opened connection) :
var session = require('express-session');
var MongoStore = require('connect-mongo')(session);
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/sess');
app.use(express.session({
secret:'secret',
maxAge: new Date(Date.now() + 3600000),
store: new MongoStore(
// Following lines of code doesn't work
// with the connect-mongo version 1.2.1(2016-06-20).
// {db:mongoose.connection.db},
// function(err){
// console.log(err || 'connect-mongodb setup ok');
// }
{mongooseConnection:mongoose.connection}
)
}));
you can read more about it here: https://github.com/kcbanner/connect-mongo
i use connect-mongo like so:
var MongoStore = require('connect-mongo');
var sess_conf = {
db: {
db: mydb,
host: localhost,
collection: 'usersessions' // optional, default: sessions
},
secret: 'ioudrhgowiehgio'
};
app.use(express.session({
secret: sess_conf.secret,
maxAge: new Date(Date.now() + 3600000),
store: new MongoStore(sess_conf.db)
}));
[...]
// Initialize Passport! Also use passport.session() middleware, to support
// persistent login sessions (recommended).
app.use(passport.initialize());
app.use(passport.session());
This is because you use MemoryStore (default) for sessions. Look at this code from memory.js (part of Connect framework):
var MemoryStore = module.exports = function MemoryStore() {
this.sessions = {};
};
and this snippet from session.js (Express)
function session(options){
/* some code */
, store = options.store || new MemoryStore
/* some code */
}
Now you should understand that every server restart resets the MemoryStore. In order to keep the data you have to use some other session store. You can even write your own (shouldn't be too difficult), although Redis (see this library) might be a good choice (and it is well supported by Express).
// EDIT
According to the Connect documentation it is enough for you if you implement get, set and destroy methods. The following code should work:
customStore = {
get : function(sid, callback) {
// custom code, for example calling MongoDb
},
set : function(sid, session, callback) {
// custom code
},
destroy : function(sid, callback) {
// custom code
}
}
app.use(express.session({
store: customStore
}));
You just need to implement calling MongoDb (or any other Db although I still recommend using nonpermament one like Redis) for storing session data. Also read the source code of other implementations to grab the idea.
This is probably obvious to experienced node users but it caught me out:
You need to configure the node session - e.g.
app.use(session({secret: "this_is_secret", store: ...}));
before initializing the passport session - e.g.
app.use(passport.initialize());
app.use(passport.session());
If you call passport.session() first it won't work (and it won't warn you). I thought the problem was with the serialize/deserialize user functions and wasted hours.
I'm using mongoose, I tried the code presented in the answers above and it didn't work for me. I got this error when I did:
Error: db object already connecting, open cannot be called multiple times
However, this works for me:
app.use(express.session({
secret:'secret',
maxAge: new Date(Date.now() + 3600000),
store: new MongoStore({mongoose_connection:mongoose.connection})
}))
Note: If you don't have MongoStore for whatever reason, you need to do:
npm install connect-mongo --save
then:
var MongoStore = require('connect-mongo')(express)
What I ended up doing:
var expressSession = require('express-session');
var redisClient = require('redis').createClient();
var RedisStore = require('connect-redis')(expressSession);
...
app.use(expressSession({
resave: true,
saveUninitialized: true,
key: config.session.key,
secret: config.session.secret,
store: new RedisStore({
client: redisClient,
host: config.db.host,
port: config.db.port,
prefix: 'my-app_',
disableTTL: true
})
}));
Works for me.
You need to change the store you are using for your sessions. The default one 'MemoryStore' does not continue to store the session when you're application stops. Check out express-session on github to find out more about what other stores there are like the mongo one. (Can't remember the name)

nodejs session storage

In the connect-mongodb module we can store session in MongoDB like this:
var connect = require('connect')
, Db = require('mongodb').Db
, Server = require('mongodb').Server
, server_config = new Server('localhost', 27017, {auto_reconnect: true, native_parser: true})
, db = new Db('test', server_config, {})
, mongoStore = require('connect-mongodb');
connect.createServer(
connect.bodyParser(),
connect.cookieParser(),
connect.session({
cookie: {maxAge: 60000 * 20} // 20 minutes
, secret: 'foo'
, store: new mongoStore({db: db})
})
);
In the example above we have to use native mongodb stuff. In my nodejs project I use mongoose 2.4.1 so how should rewrite that code to use mongoose?
Thanks!
If you are using mongoose and you used mongoose.connect, you can get the connection at
mongoose.connection
So to configure the session store you can use this form
var mongoose = require('mongoose'),
mongoStore = require('connect-mongodb');
...
mongoose.connect(host,databaseName,port);
// mongoose.connect('mongodb://host:port/databaseName');
...
connect.session({
secret: 'your secret key',
cookie: { maxAge : 60*15*1000}, // 15 minutes, in milliseconds
store: new mongoStore( { db : mongoose.connection.db })
})
You have no reason to do that, just use sessions with connect-mongodb which has all the 'Session Store' Express functionality implemented. Use Mongoose for everything else which requires db storage, but leave the sessions for connect-mongodb.
Here's a real example that does that: https://github.com/alexyoung/nodepad
Mongoose should expose the connection somehow.
If you use connect-mongo, pass your mongoose connection like this:
var express = require('express');
var MongoStore = require('connect-mongo')(express);
new MongoStore({ mongoose_connection: mongoose.connection })
And everything will work as you'd expect.

Resources