3

I'm building a Node application in which the users must register or login, then when they drag and drop some elements (the front end is all working) I store on the database their action with their corresponding userId.

My understanding is that once they are registered/logged in, I can use the req.user to access their id and correctly store their actions, however it isn't working.

Here is the section of my server.js file that deals with Passport. Also, I'm using Sequelize as an ORM, but everything dealing with the database works perfect without the req.user part.

app.use(cookieParser());
app.use(bodyParser.json());

app.use(passport.initialize());
app.use(passport.session());

/****** Passport functions ******/
passport.serializeUser(function (user, done) {
    console.log('serialized');
    done(null, user.idUser);
});

passport.deserializeUser(function (id, done) {
    console.log("start of deserialize");
    db.user.findOne( { where : { idUser : id } } ).success(function (user) {
        console.log("deserialize");
        console.log(user);
        done(null, user);
    }).error(function (err) {
        done(err, null);
    });
});

//Facebook
passport.use(new FacebookStrategy({
    //Information stored on config/auth.js
    clientID: configAuth.facebookAuth.clientID,
    clientSecret: configAuth.facebookAuth.clientSecret,
    callbackURL: configAuth.facebookAuth.callbackURL,
    profileFields: ['id', 'emails', 'displayName', 'name', 'gender'] 

}, function (accessToken, refreshToken, profile, done) {
    //Using next tick to take advantage of async properties
    process.nextTick(function () {
        db.user.findOne( { where : { idUser : profile.id } }).then(function (user, err) {
            if(err) {
                return done(err);
            } 
            if(user) {
                return done(null, user);
            } else {
                //Create the user
                db.user.create({
                    idUser : profile.id,
                    token : accessToken,
                    nameUser : profile.displayName,
                    email : profile.emails[0].value,
                    sex : profile.gender
                });

                //Find the user (therefore checking if it was indeed created) and return it
                db.user.findOne( { where : { idUser : profile.id } }).then(function (user, err) {
                    if(user) {
                        return done(null, user);
                    } else {
                        return done(err);
                    }
                });
            }
        });
    });
}));

/* FACEBOOK STRATEGY */
// Redirect the user to Facebook for authentication.  When complete,
// Facebook will redirect the user back to the application at
//     /auth/facebook/callback//
app.get('/auth/facebook', passport.authenticate('facebook', { scope : ['email']}));
/* FACEBOOK STRATEGY */
// Facebook will redirect the user to this URL after approval.  Finish the
// authentication process by attempting to obtain an access token.  If
// access was granted, the user will be logged in.  Otherwise,
// authentication has failed.

    app.get('/auth/facebook/callback',
        passport.authenticate('facebook', { failureRedirect: '/' }),
        function (req, res) {
            // Successful authentication, redirect home.
            res.redirect('../../app.html');
        });


app.get('/', function (req, res) {
    res.redirect('/');
});

app.get('/app', isLoggedIn, function (req, res) {
    res.redirect('app.html');
});

app.post('/meal', function (req, res) {
    //Testing Logs
        /*console.log(req.body.foodId);
        console.log(req.body.quantity);
        console.log(req.body.period);
        console.log(req.body);
        */

    //Check whether or not this is the first food a user drops on the diet
    var dietId = -1;

    db.diet.findOne( { where : { userIdUser : req.user.idUser } } ).then(function (diet, err) {
        if(err) {
            return done(err);
        }
        if(diet) {
            dietId = diet.idDiet;
        } else {
            db.diet.create( { userIdUser : req.user.idUser }).then(function (diet) {
                dietId = diet.idDiet;
            });
        }
    });

    db.meal.create({
        foodId : req.body.foodId,
        quantity : req.body.quantity,
        period : req.body.period
    }).then(function (meal) {
        console.log(meal.mealId);
        res.json({ mealId : meal.mealId});
    });
});

From what I read on the documentation for Passport, the deserializeUser function that I implemented should be called whenever I use req.user, however, with my console.logs(), I found out that serializeUser is called after logging in, therefore it is storing my session, but deserializeUser is never called! Ever.

Any idea on how to get around this? Any help is appreciated, thank you!

leofontes
  • 898
  • 4
  • 16
  • 40

2 Answers2

8

You need the express session middleware before calling passport.session(). Read the passportjs configuration section on documentation for more info.

yeiniel
  • 2,416
  • 15
  • 31
  • Thank you so much! I just have a follow up question, what is the "store" and why would I need to use it? I mean, why would I need another module to store those informations? Aren't cookies enough? – leofontes Jun 24 '16 at 16:26
  • 3
    A session store is a way to store the session information outside of the Nodejs process running your express app. By default the session middleware use an in-memory store suitable only for development purposes. Once you enter production stage (multiple node processes behind load balancer) the default session store will not work any more for you. You can use cookies to store the session information but always remember that cookie size is very limited and you may have some sensible information you don't want to travel over the network event encrypted. – yeiniel Jun 24 '16 at 16:29
1
  1. Make sure to set cookieParser and express-session middlewares, before setting passport.session middleware:
const cookieParser = require('cookie-parser')
const session = require('express-session')
app.use(cookieParser());
app.use(session({ secret: 'secret' }));
app.use(passport.initialize());
app.use(passport.session());
  1. To test if passport session is working or not, use:
console.log(req.session.passport.user)

(put in on a middleware for example)

  1. In my case, i was using LocalStrategy and i was thinking i can protect and endpoint with simple username and password as form parameters, and i though passport will only use form parameters when it can't find user in session. but it was wrong assumption. in passport localStrategy, you should have separate endpoints for login and protected endpoint.

So Make sure you're using right middlewares for each endpoints. in my case:

wrong:

Protected endpoint:

app.get('/onlyformembers', passport.authenticate('local'), (req, res) => {
  res.send({"res": "private content here!"})
})

correct :

Login:

app.post('/login', passport.authenticate('local'), (req, res) => {
  res.send('ok')
})

Protected endpoint:

var auth = function (req, res, next) {
  if (req.isAuthenticated())
    return next();
  res.status(401).json("not authenticated!");
}

app.get('/onlyformembers', auth, (req, res) => {
  res.send({"res": "private content here!"})
})
yaya
  • 7,675
  • 1
  • 39
  • 38