2
votes

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!

2

2 Answers

8
votes

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

1
votes
  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!"})
})