Matan Givoni
Matan Givoni

Reputation: 1126

Staying authenticated after the page is refreshed using Passportjs

I am building a SPA using express, mongoose and passportjs.

I have created a simple schema for my user:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var passportLocalMongoose = require('passport-local-mongoose');

var User = new Schema({
    username: String,
    password: String,
    first_name: String
}, { collection: 'users' });

User.plugin(passportLocalMongoose);

mongoose.model('User', User);

Configured passport using the User object which mongoose gave me:

passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());         
passport.deserializeUser(User.deserializeUser());

And configured my app to authenticate the user when navigating to this route:

app.post('/login', passport.authenticate('local'), function(req, res, next) {
    if (req.isAuthenticated()) {
        return res.json({ state: 'success', user: { first_name: req.user.first_name } });    
    }
    return res.json({ state: 'failure', message: 'cannot authenticate' });
});

Now I am able to successfully authenticate a user. And the browser saves a session id cookie.

My problem is that every time the user refreshes the page passport won't deserialize the user using the session id, what makes the user unauthenticated.

While accessing the req.user object in the site's root I get undefined what make me realize passport doesn't deserialize the user properly:

app.use('/', function (req, res, next) {
    console.log(req.user); // prints undefined.        

    next();
});

What is the proper way for restoring a user after refreshing the page?

Upvotes: 5

Views: 4875

Answers (2)

Matan Givoni
Matan Givoni

Reputation: 1126

The solution is to store the sessions in the DB. I used connect-mongo.

app.js:

var mongoose = require('mongoose');
var expressSession = require('express-session');
var MongoStore = require('connect-mongo')(expressSession);

mongoose.connect(db_url, function (err) {
    if (err) {
        console.log(err);
    }
});

app.use(expressSession({
    secret: process.env.SESSION_SECRET || 'keyboard cat',
    resave: false,
    saveUninitialized: false,
    store: new MongoStore({ mongooseConnection: mongoose.connection })
}));

after this, req.isAuthenticated() returns true on every request even after refreshing the page. (Thanks to app.use(passport.session()) which comes before any route handler)

app.use('/', function (req, res, next) {
    if (req.isAuthenticated()) {
        // returns true if a user already logged in.
    }
    next();
});

Upvotes: 5

NarendraSoni
NarendraSoni

Reputation: 2258

Looking at your post i can guess where problem is happening. In question you have pasted your back end expressjs code, but the problem is happening in the front end.

Think of a situation when you are working on normal javascript files, you make some edit in the variable values using Chrome dev tools of firebug n all. Let's say you refresh the page, do you still see the same edited value in the view? No right. Same is the case with your view, you are temporary holding user data. Although your backend is holding the values in req.user but your front end loses it when you refresh.

So you have to do either of below two :

  • Store your value in cookie on successful login and erase it when logged out. So that cookie is never going to loose data even if you refresh the page. Access the user data from that cookie whenever you need it
  • Call the backend API which returns value of req.user on your every page refresh

I am not sure what frontend framework you are using for SPA, if you are using AngularJS then you can make use of cookieStore service it does the job beautifully.

Upvotes: 0

Related Questions