I am using passport.js + passport-facebook-token to secure my API build with Strongloop's Loopback Framework.
Why is passport serializing the deserialized user again after it has successfully been deserialized? Also the passport.authenticate method is called on every request! What am I doing wrong?
Here is node's log:
deserializeUser, id: XXXXXXXXXXXXXXXX
User found.
serializeUser, id: XXXXXXXXXXXXXXXX
GET /api/events?access_token=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 304 182ms
Here is the js code:
passport.use(new FacebookTokenStrategy({
clientID: XXXXXXXXXXXXXXXX,
clientSecret: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXX'
},
function(accessToken, refreshToken, profile, done) {
//check user table for anyone with a facebook ID of profile.id
User.findOne({
'facebookId': profile.id
}, function(err, user) {
if (err) {
return done(err);
}
if (user) {
console.log("User found.");
return done(err, user);
} else {
console.log("User not found.");
User.create({
email: profile.emails[0].value,
facebookId: profile.id,
password: 'secret'
}, function(err, user) {
console.log(user.id);
console.log(user.email);
console.log(user.facebookId);
console.log("User created");
return done(err, user);
});
}
});
}));
passport.serializeUser(function(user, done) {
console.log('serializeUser, id: ' + user.facebookId);
done(null, user.facebookId);
});
passport.deserializeUser(function(id, done) {
console.log('deserializeUser, id: ' + id);
User.findOne({
'facebookId': id
}, function(err, user) {
if (!err) {
done(null, user);
} else {
done(err, user);
}
});
});
Regarding your question about why passport.authenticate
is called on every request, it is because you defined it as a middleware, probably before any routing logic happens.
If you have private and public sections on your app, you could do something like that :
// Define a specific that will handle authentication logic
app.get("/auth", passport.authenticate('facebook-token',function(){...});
// Public sections which do not require authentication
app.get("/public1",...);
app.post("/public2",...);
// Private sections which do require authentication
app.get("/private1", function(req,res,next){
if (req.isAuthenticated()){ // Check if user is authenticated
// do things...
}else{ // Wow, this guy is not authenticated. Kick him out of here !
res.redirect("/auth");
}
});
Now, if you have multiple private sections, you'll probably find it a bit tidious to do the same thing for each private section. You could define a custom function that will check if the user is authenticated, and allow the request to proceed if he is. Something like
function isThisGuyAuthenticated(req,res,next){
if (req.isAuthenticated()){
return next(); // Ok this guy is clean, please go on !
}else{
res.redirect("/auth"); // This guy is shady, please authenticate !
}
}
And use it like :
app.get("/private1",isThisGuyAuthenticated, doCrazySecretStuff); // doCrazySecretStuff will not be called if the user is not authenticated
app.get("/private2", isThisGuyAuthenticated, getCocaColaRecipe);
app.get("/private3", isThisGuyAuthenticated, flyToMars);
app.get("/public", showInfo); // showInfo will be called whether the user is authenticated or not
Now, if your app only has private sections, you could avoid repeating calls to isThisGuyAuthenticated
by defining it as middleware (but not by defining passport.authenticate
itself as a middleware !);
// Endpoint that will be hit is the user is redirected to /auth
// BEWARE it needs to be above the middleware, otherwise you'll end up with an infinite redirection loop
app.get("/auth", passport.authenticate('facebook-token',function(){...});
// Middleware that will be called on every request
app.use(isThisGuyAuthenticated);
// You app's endpoints
app.get("/private1", doCrazySecretStuff); // doCrazySecretStuff will not be called if the user is not authenticated
app.get("/private2", getCocaColaRecipe);
app.get("/private3", flyToMars);
Is that clear ?
EDIT : I mistakenly put the middleware before the "/auth" endpoint. Make sure it's placed after
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With