Can't use mongo based session store - node.js

I have a mongoose and connect-mongo module instance in ym app. I am using the connect-mongo module to have a session store persisted in a mongodb database (mongohq) instead of a memory store.
Everytime I try to access my app when the server is launched (facebook auth with everyauth) I get the following:
500 MongoError: Error: unauthorized db:express-sessions lock type:-1
client:199.192.242.4
My user name, password are good.
var conf = {
db: {
db: 'express-sessions',
host: 'staff.mongohq.com',
port: 10072, // optional, default: 27017
username: 'admin', // optional
password: 'admin', // optional
collection: 'facebookSessions' // optional, default: sessions
},
secret: '076ee61d63aa10a125ea872411e433b9'
};
app.use(express.session({
secret: conf.secret,
maxAge: new Date(Date.now() + 3600000),
store: new MongoStore(conf.db)
}));
Edit, this seems to be an issue with my mongohq. I modified the collection for an older one and it works.

I was facing a similar error using Heroku and Mongolab.
I resolved it by manually create a new database user with the mongolab web admin.

It sounds like the db was started with --auth but the user has not been granted access to the db.
http://www.mongodb.org/display/DOCS/Security+and+Authentication

Related

Keep user sessions logged in on Node.js server restart

I am using express-session for a login system for users on my Node.js web application. My issue is that every time I make an update and restart the Node.js server, all the users are logged off which is not ideal behaviour (there are multiple users logged on via the local network and I would like to not have to log them back on each time there is a restart).
From my understanding I could use something such as connect-pg-simple (for reference I am using a postgres database with my node web app) to keep users logged in on server restart but I am unsure of how to implement this.
I know it would be something along the lines of:
app.use(session({
store: new (require('connect-pg-simple')(session))({
// Insert connect-pg-simple options here
}),
secret: 'secret',
resave: false,
saveUninitialized: true
}));
But I do not know what options to use or how to save the users session even on server restart.
Yes you are on the right track.
Open your database and create a table named session. See: https://github.com/voxpelli/node-connect-pg-simple/blob/HEAD/table.sql
Add the connect-pg-simple code like you posted
Pass the postgres pool you are using from node-pg.
const session = require('express-session')
const PGSessionStore = require('connect-pg-simple')(session)
const pg = require('pg')
const pool = new pg.Pool({
user: process.env.PG_USERNAME,
host: process.env.PG_HOST,
database: process.env.PG_DATABASE,
password: process.env.PG_PASSWORD,
port: process.env.PG_PORT
})
app.use(session({
store: new PGSessionStore({
pool: pool,
tableName: 'session'
}),
secret: process.env.COOKIE_SECRET,
cookie: {
secure: false,
httpOnly: true,
sameSite: true,
maxAge: 24 * 60 * 60 * 1000
},
saveUninitialized: true,
resave: false
}))
Your session is stored on the app runtime, so on refresh, it resets back every other data it might be holding at runtime on server restart

Mongoose and connect-mongo

I am using mongoose for managing relationships between data and I am trying to use connect-mongo to store specific sessions in the database.
It looks like that we need to connect twice to the db, one with mongoose and another one with connect-mongo.
I am using the following code to initialise a connection for mongoose
await mongoose.connect(this._connectionUrl, this._connectionOptions);
Initialising a new store every time (not sure if I am correct regarding code initialisation).
app.use(session({
// secret: config.sessionSecretKey,
secret: "secretkey",
resave: true,
saveUninitialized: true,
cookie: { maxAge: 19 * 60000 }, // store for 19 minutes
store: MongoStore.create({
mongoUrl: this._connectionUrl,
mongoOptions: this._connectionOptions // See below for details
})
}))
Is there any way that I can pass the connection from mongoose to mongo-connect Store?
i'm lookin for a solution too and just read this on the "migration guide" of connect-mongo
For the options, you should make the following changes:
Change url to mongoUrl Change collection to collectionName if you are
using it Keep clientPromise if you are using it mongooseConnection has
been removed. Please update your application code to use either
mongoUrl, client or clientPromise To reuse an existing mongoose
connection retreive the mongoDb driver from you mongoose connection
using Connection.prototype.getClient() and pass it to the store in the
client-option. Remove fallbackMemory option and if you are using it,
and there's this example https://github.com/jdesboeufs/connect-mongo/blob/master/example/mongoose.js
I've just been digging through the docs and through a few other SO responses. I've found this works really well with the new version of connect-mongo.
const session = require('express-session');
const MongoStore = require('connect-mongo');
app.use(
session({
secret: "secretkey",
resave: true,
saveUninitialized: true,
cookie: { maxAge: 19 * 60000 }, // store for 19 minutes
store: MongoStore.create({
client: mongoose.connection.getClient()
})
})
);
It is recommended by the devs for connect-mongo to utilise the connection object for mongoose to retrieve the client to ride the same connection so you don't have to setup two separate connections. This seems like a really clean way to do it but comment if you spot anything off!
This was pulled from the bottom of the connect-mongo migration guide here

connect-redis not storing session

I've been trying to use connect-redis to use express session store with AWS Elasticache.
The redis server at AWS I used is using Encryption in-transit, encryption at-rest and Redis AUTH token.
i am using Passport with local strategy to authenticate users
This is how it looks in app.js when I configure it:
const express = require('express'),
app = express(),
session = require('express-session'),
awsHandler = require('./awsHandler'),
passport = require('passport'),
....
....
awsHandler.retrieveServiceCredentials('session').then(keys => {
let secret = keys.session_key;
let redis_auth = keys.redis_auth;
const redis = require('redis');
const redisClient = redis.createClient({
host: 'master.redis-connect.abcd.efg.cache.amazonaws.com',
port: REDIS_PORT,
auth_pass: redis_auth,
tls: { checkServerIdentity: () => undefined }
});
const redisStore = require('connect-redis')(session);
app.use(session({
secret: secret,
resave: false,
saveUninitialized: false,
store: new redisStore({
client: redisClient
})
}));
});
....
....
app.use(passport.initialize());
app.use(passport.session());
The thing is I try to connect to my website, and I get no req.session or req.user (when before using SQLite with connect-sqlite3 package, I had req.user after logging in).
I noticed nothing gets stored in redis, when I connect to the Redis Server and type KEYS * there are no keys. However, when I try to set a key in the Redis server hardcoded in app.js with:
redisClient.set('key', 'value')
It IS setting the key and value in the server (when typing KEYS * we can see it there).
So I do successfully establish connection to the redis server with the client library, however, it seems something happens there that I don't configure properly so the sessions gets stored in the Redis.
I am on AWS environment (Elastic Beanstalk, Elasticache).
hank you for reading and helping!
Best regards.
I solved it, it was a problem in my code :
the awsHandler.retrieveServiceCredentials is an async function, and called after couple seconds.
In the flow, it was already initializing everything in the app (initializing passport session, defining routes, starting the node server to listen on port, etc...), and because the retrieveServiceCredentials returned later than that, the order was wrong, and it initialized everything in the app before we used app.use(prodSessionMiddleware), so therefore the session not included in the app.
We set an interval every second, and check a boolean if the 'then' was called, if it was called, we clear the interval and continue with our life :)

Express 4 Sessions not persisting when restarting server

I have an Express 4 app setup to have sessions.
// Sessions
app.use(cookieParser());
app.use(session({ secret: "some-secret" }));
// Signup
app.post("/signup", function (req, res) {
create_user(req.body.user, function (err, user_id) {
req.session.user_id = user_id;
res.redirect("/admin");
});
});
When I submit the form, it saves the user_id to the req.session. However, when I restart the server, the session is gone.
Why isn't it persisting? Am I missing some configuration?
The default session store for express-session is MemoryStore, which as the name suggests, stores sessions in memory only. If you need persistence, there are many session stores available for Express. Some examples:
Cookie store
Redis store
MongoDB store
CouchDB store
Riak store
memcached store
leveldb store
MySQL store
PostgreSQL store
Firebase store
For a updated and more complete list visit Compatible Session Stores.
#mscdex answer is great but in case you are looking for code samples. Here is one with connect-mongo which should work fine if you mongodb and mongoose.
Install the package:
npm i connect-mongo
require the package:
const session = require('express-session'); // You must have express-sessions installed
const MongoStore = require('connect-mongo')(session)
Now configure the session:
app.use(
session({
secret: "mysecrets",
resave: false,
saveUninitialized: false,
store: new MongoStore({
mongooseConnection: mongoose.connection,
ttl: 14 * 24 * 60 * 60
}),
})
);
Again this assumes you are using mongoose and have the connection configured.
If you did everything right, it should work just fine.

Store sessions in mongodb with connect-mongo and mongoose

I am getting errors left and right while I try to configure the express.js session storage with mongodb. I am using locomotive for my framework and have configured mongoose.
In my initializers directory for 02_mongoose.js I have this.
module.exports = function() {
mongoose.connect('mongodb://localhost:27018/basbac');
mongoose.model('User', UserSchema);
}
I know I have a connection to the database because I can pull my users in my controller.
DeveloperController.show = function() {
var self = this;
var user = mongoose.model('User');
user.find().exec(function(error, users) {
if(error) {
console.log(error);
} else {
self.res.json({response: { id: self.param('id'), api: self.param('api'), users: users } });
}
});
}
http://localhost:3000/developer/test/?api=hhfkgjhukdsfkjhvsduhvudhcsiudvlskejfbk
{
response: {
id: "test",
api: "hhfkgjhukdsfkjhvsduhvudhcsiudvlskejfbk",
users: [
{
_id: "52706695a43c83a739358de5",
firstname: "cad",
lastname: "bane",
address: "duro",
email: "cad#bane.com"
},
{
_id: "52706695a43c83a739358de6",
firstname: "jar jar",
lastname: "binks",
address: "naboo",
email: "jarjar#binks.com"
}
]
}
}
Inside my config/all.js I have this as my configuration for sessions
var MongoStore = require('connect-mongo')(express);
var mongoose = require('mongoose');
this.use(express.cookieParser());
this.use(express.session({
secret: 'keyboard cat',
store: new MongoStore({
mongoose_connection: mongoose.connection
})
}));
But this throws an error.
this.db = new mongo.Db(options.mongoose_connection.db.databaseName,
TypeError: Cannot read property 'databaseName' of undefined
I also tried to do it like the connect-mongo docs where saying but I get an error with that as well. (https://github.com/kcbanner/connect-mongo) mongoose_connection in the form: someMongooseDb.connections[0] to use an existing mongoose connection. (optional)
this.use(express.session({
secret: 'keyboard cat',
store: new MongoStore({
mongoose_connection: mongoose.connections[0]
})
}));
But I get the same error as before.
this.db = new mongo.Db(options.mongoose_connection.db.databaseName,
TypeError: Cannot read property 'databaseName' of undefined
I also tried to do as many articles are saying to do. Here is one for example of someones working configuration (Logout in ExpressJS, PassportJS and MongoStore)
this.use(express.session({
secret: 'keyboard cat',
store: new MongoStore({
db: mongoose.connection.db
})
}));
But that also produces an error, and I know that the db key is actually undefined
throw new Error('Required MongoStore option `db` missing');
What am I doing wrong to pass this connection into the new MongoStore? When I start console.log() the mongoose object I am not able to find any information about the connection it is using. I do see a base object but it does not have a db key inside it. Do I need to pass some more options into the mongoose configuration?
The problem is the order in which Locomotive starts up. According to the docs:
When a Locomotive application is started, it proceeds through a
sequence of steps:
Configure the Environment
In this step, config/environments/all.js is executed followed by the
configuration file for the current environment. For instance, when
running in development, config/environments/development.js is
executed.
Invoke Initializers
After the environment has been configured, initializers are invoked.
Initializers are used to configure sub-systems and connect to
databases, message queues, and other services utilized by the
application.
So when your environment code is being called, the initializer hasn't yet run and Mongoose isn't configured. Try moving the Mongoose setup to a separate file (I use app/db/mongoose myself, but that's a matter of personal preference) and require that in your environment file.

Resources