req.user after restart node - node.js

I've attached passportjs to authenticate user on my site. I use localStrategy and all works fine. But I have some problem (may be it's feature of passportjs) - after restart node, req.user is undefined and users should login again.
What should I do to initialize req.user on start server??

LocalStrategy stores user credentials in memory after login. This means that when you restart node, the credentials will inevitably be lost.
However, passport does use the session cookie functionality in express, so you can persist cookies in the standard express way.
This is quite easy using the RedisStore module, to which you pass the express object:
var express = require('express');
var RedisStore = require('connect-redis')(express);
Before you set up passport, enable session persistence to redis in express:
app.use(express.cookieParser());
app.use(express.session({
secret: "a-secret-token",
store : new RedisStore({
host : 'redis-hostname',
port : 'redis-port',
user : 'redis-username',
pass : 'redis-password'
}),
cookie : {
maxAge : 604800 // one week
}
}));
app.use(passport.initialize());
app.use(passport.session());
You'll need to install redis on your machine, and change the details above to match the redis instance you want to connect to.

You need to store user login info in Redis for e.g. because after restart, all your variables that you set will be undefined

Related

How can I use the same Express session for multiple hostnames?

So I have a Node.js + Express app I can access with a couple of hostnames: example1.com and example2.com (they are not subdomain! I know how to do it if they are subdomains).
I use Express Session with MongoDB Store and passport to manage authentication.
I'd like to use the same session with both the domains but I can't
figure out how to do it.
Each time I access the two domains it creates two different sessions and I cannot understand where I could check if the session is already up and use that for both the domains.
Basically this is my current express init file (I removed a lot of things, just to focus on sessions):
'use strict';
/**
* Module dependencies.
*/
var express = require('express'),
bodyParser = require('body-parser'),
session = require('express-session'),
cookieParser = require('cookie-parser'),
passport = require('passport'),
MongoDBStore = require('connect-mongodb-session')(session),
config = require('./config');
module.exports = function(db) {
// Initialize express app
var app = express();
// CookieParser should be above session
app.use(cookieParser());
var store = new MongoDBStore(
{
uri: config.db,
collection: config.sessionCollection
});
// Express MongoDB session storage
app.use(session({
saveUninitialized: true,
resave: true,
secret: config.sessionSecret,
store: store,
}));
app.use(passport.initialize());
app.use(passport.session());
return app;
};
Any hint?
IMO the only way to do that is, if you are able to figure out on server side that the request is coming from the same browser/machine. Because, browser would not the share the session Id cookie(as the requests are for two different domains) and on server you would think it of as a new request for session, and you would always grant a new sessionId to the client.
If you really want to have single session store, I recommend writing your own session store with the below idea:
Firstly, don't use cookies for session, and use browser's localstorage and sign the sessionId from the server that needs to be stored on the client, which protects it from being tampered. This session Id would be included in the requests using your AJAX and client-side JS in each requests acting as a sessionId cookie.
Secondly, Open an iframe of the other domains when ever a domain is opened, let say if example1.com is opened you should open an iframe of example2.com and vice-versa. In your iframes write code to send signed localstorage information back to parent frame using window.postMessage() Since, you are owner of all the domains you should be able to allow window.postMessage() communication across your domains.
Since, you would receive the same session Id in each request across all domains you can detect unique session across domains and devise session store on server side to store only one entry across domains.

Express.js sessions reset at server restart

I am using the express-session package with a custom MongoDB based session store, but for some reason the sessions are deleted everytime I stop and re-run the script.
From looking at the database I can see that the sessions are saved.
Any ideas?
You can use connect-mongo for storing sessions in database so that it would persist even after restarting the node server.
Here is an example on how you can use it. Example is from its Readme.
var session = require('express-session');
var MongoStore = require('connect-mongo')(session);
app.use(session({
secret: settings.cookie_secret,
store: new MongoStore({
db : settings.db,
})
}));

CouchDB with NodeJS authentication solution

In node.js my auth library (lockit) is not setting session after logging in successfully. (Disclaimer: I am not condoning the use of lockit, I think it is positively terrible in every way.)
I read lockit source code and found this code:
// create session and save the name and email address
req.session.name = user.name;
req.session.email = user.email;
Here is my express config:
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.use(cookieParser());
app.use(cookieSession({
secret: 'this is my super secret string'
}));
app.use(lockit.router);
After I login with a user, I send another request with the same browser and the cookie is the same that gets set from the login request...
After successful login here is the Set-Cookies I get:
Set-Cookie express:sess=eyJmYWlsZWRMb2dpbkF0dGVtcHRzIjowLCJuYW1lIjoianVzdGluIiwiZW1haWwiOiJqdXN0aW5Ad2ViaW52ZXJ0ZXJzLmNvbSIsImxvZ2dlZEluIjp0cnVlfQ==; path=/; httponly
Set-Cookie express:sess.sig=FMcv9fswWmWG6A7hpOEnEysbqd4; path=/; httponly
Then my request after the login contains these cookies:
express:sess eyJmYWlsZWRMb2dpbkF0dGVtcHRzIjowLCJuYW1lIjoianVzdGluIiwiZW1haWwiOiJqdXN0aW5Ad2ViaW52ZXJ0ZXJzLmNvbSIsImxvZ2dlZEluIjp0cnVlfQ==
express:sess.sig FMcv9fswWmWG6A7hpOEnEysbqd4
But even though the cookie is there, I'm getting:
req.session === undefined
I've never used these technologies before, so it could be something really stupid that I am doing...
I'm the author of Lockit and I'm sure we will find a solution to your problem. Did you go through all the required steps to install Lockit? Here is what I just did and it works fine.
Create a new Express app (Express 4.2.0 in my case).
express
Install Express dependencies.
npm install
Install Lockit and Sessions.
npm install lockit cookie-session --save
Install CouchDB adapter.
npm install lockit-couchdb-adapter --save
Create a config.js with the URL of your CouchDB
// settings for local CouchDB
exports.db = 'http://127.0.0.1:5984/';
Initiate Lockit with your config.
// in your header
var cookieSession = require('cookie-session');
var Lockit = require('lockit');
var config = require('./config.js');
var lockit = new Lockit(config);
// after all your other middleware
app.use(cookieSession({
secret: 'my super secret String'
}));
app.use(lockit.router);
Start your app.
DEBUG=tmp ./bin/www
You can now navigate to http://localhost:3000/signup and create a new user. If you haven't set up any email server you have to look in your database (in my case at http://127.0.0.1:5984/_utils/database.html?_users) for your signup token. Then go to http://localhost:3000/signup/:token to activate your new user.
Great, you can now use your username (or email) and password to log in. To access the currently logged in user in your own routes use req.session.
// default routes from Express
app.use('/', routes);
app.use('/users', users);
// your own custom route
app.get('/awesome', function(req, res) {
console.log(req.session.name);
console.log(req.session.email);
res.send('awesome');
});
I hope I could help you. If you've got any other problems just let me know.
http://localhost:3000/signup/:token doesn't work, must be
http://localhost:3000/signup/token (without the column)

What does passport.session() middleware do?

I am building an authentication system using Passport.js using Easy Node Authentication: Setup and Local tutorial.
I am confused about what passport.session() does.
After playing around with the different middleware I came to understand that express.session() is what sends a session ID over cookies to the client, but I'm confused about what passport.session() does and why it is required in addition to express.session().
Here is how I set up my application:
// Server.js configures the application and sets up the webserver
//importing our modules
var express = require('express');
var app = express();
var port = process.env.PORT || 8080;
var mongoose = require('mongoose');
var passport = require('passport');
var flash = require('connect-flash');
var configDB = require('./config/database.js');
//Configuration of Databse and App
mongoose.connect(configDB.url); //connect to our database
require('./config/passport')(passport); //pass passport for configuration
app.configure(function() {
//set up our express application
app.use(express.logger('dev')); //log every request to the console
app.use(express.cookieParser()); //read cookies (needed for auth)
app.use(express.bodyParser()); //get info from html forms
app.set('view engine', 'ejs'); //set up ejs for templating
//configuration for passport
app.use(express.session({ secret: 'olhosvermelhoseasenhaclassica', maxAge:null })); //session secret
app.use(passport.initialize());
app.use(passport.session()); //persistent login session
app.use(flash()); //use connect-flash for flash messages stored in session
});
//Set up routes
require('./app/routes.js')(app, passport);
//launch
app.listen(port);
console.log("Server listening on port" + port);
passport.session() acts as a middleware to alter the req object and change the 'user' value that is currently the session id (from the client cookie) into the true deserialized user object.
Whilst the other answers make some good points I thought that some more specific detail could be provided.
app.use(passport.session());
is equivalent to
app.use(passport.authenticate('session'));
Where 'session' refers to the following strategy that is bundled with passportJS.
Here's a link to the file:
https://github.com/jaredhanson/passport/blob/master/lib/strategies/session.js
And a permalink pointing to the following lines at the time of this writing:
var property = req._passport.instance._userProperty || 'user';
req[property] = user;
Where it essentially acts as a middleware and alters the value of the 'user' property in the req object to contain the deserialized identity of the user. To allow this to work correctly you must include serializeUser and deserializeUser functions in your custom code.
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(function (user, done) {
//If using Mongoose with MongoDB; if other you will need JS specific to that schema.
User.findById(user.id, function (err, user) {
done(err, user);
});
});
This will find the correct user from the database and pass it as a closure variable into the callback done(err,user); so the above code in the passport.session() can replace the 'user' value in the req object and pass on to the next middleware in the pile.
From the documentation
In a Connect or Express-based application, passport.initialize()
middleware is required to initialize Passport. If your application
uses persistent login sessions, passport.session() middleware must
also be used.
and
Sessions
In a typical web application, the credentials used to authenticate a
user will only be transmitted during the login request. If
authentication succeeds, a session will be established and maintained
via a cookie set in the user's browser.
Each subsequent request will not contain credentials, but rather the
unique cookie that identifies the session. In order to support login
sessions, Passport will serialize and deserialize user instances to
and from the session.
and
Note that enabling session support is entirely optional, though it is
recommended for most applications. If enabled, be sure to use
express.session() before passport.session() to ensure that the login
session is restored in the correct order.
While you will be using PassportJs for validating the user as part of your login URL, you still need some mechanism to store this user information in the session and retrieve it with every subsequent request (i.e. serialize/deserialize the user).
So in effect, you are authenticating the user with every request, even though this authentication needn't look up a database or oauth as in the login response. So passport will treat session authentication also as yet another authentication strategy.
And to use this strategy - which is named session, just use a simple shortcut - app.use(passport.session()). Also note that this particular strategy will want you to implement serialize and deserialize functions for obvious reasons.
It simply authenticates the session (which is populated by express.session()). It is equivalent to:
passport.authenticate('session');
as can be seen in the code here:
https://github.com/jaredhanson/passport/blob/42ff63c/lib/authenticator.js#L233

How can I find the session Id when using express / connect and a session store?

If a user is already logged in and tries to login again in a new instance I'd like it to log out the other user instance. I don't want the same user to be logged in twice on my application.
Currently the session is stored in a Redis store, i'm using express / connect to handle the session storage. One of the functions available which could be used to destroy the session is as follows:
.destroy(sid, callback)
However I need to find that session id before I call .destroy(). In Redis the username is stored as a part of the session.
Question: Is it possible to query Redis to obtain the session id based on the username?
req.sessionID will provide you the session's ID, where req is a request object.
For recent readers;
Connect middlewares are not included in Express since version 4.
So in order to have req.sessionID work you must do following:
Make sure you have cookie-parser abd express-session modules inside your package.json. If it's not added, add them:
npm install express-session --save
npm install cookie-parser --save
Be careful about the order while requiring them in your app.js file and add required configuration parameters.
var cookieParser = require('cookie-parser');
var session = require('express-session')
app.use(cookieParser());
app.use(session({
secret: '34SDgsdgspxxxxxxxdfsG', // just a long random string
resave: false,
saveUninitialized: true
}));
Now you should be using req.sessionID and req.session.id.
Store the SID with the account, when the user logs in during the database validation of the user account call .destroy(sid, fn), then update the SID in the database with the current SID of the user.
In my case using MongoDB this is how i've done it:
app.post('/login', function(req, res)
{
var sid = req.sessionID;
var username = req.body.user;
var password = req.body.pass;
users.findOne({username : username, password : password}, function(err, result)
{
...
sessionStore.destroy(result.session, function(){
...
users.update({_id: result._id}, {$set:{"session" : sid}});
...
}
...
}
}
Question: Is it possible to query Redis to obtain the session id based on the username?
No. The session keys in redis are not named after the username.
Here's a thought, though: When an already logged in user tries to login again, can't you see that, in your application, and either destroy the old session immediately, or not allow them to login again?

Resources