I'm using passportJS with express to authenticate user by local strategy. I have seen few articles regarding how passport is setup and the execution flow. Although most of the thing regarding passport can be figured out by searching, there is serialization and deserialization of user which keeps me confused.
I understand it is used to save the user information in session for persistent login. My code for serialization and deserialization is
passport.serializeUser(function(user, done){
done(null, user.id);
});
passport.deserializeUser(function(id, done){
User.findById(id, function(err, user){
done(err, user);
});
});
My question regarding this
1) Who calls and populates the arguments of the serializeUser and deserializeUser? And how it has access to the user object? To understand this I added log like
passport.serializeUser(function(user, done){
console.log(arguments.callee.caller);
done(null, user.id);
});
And got [Function: pass] in output Can anyone explain this?
2) I am using mongodb to store the user information. MongoDB has _id as the default id of document. So ideally the serializeUser and deserializeUser should have worked with user._id instead of user.id. But it is working fine with user.id which is not available in User the object. Here is the user object printed in console
{ _id: 5505f231b810dbd4098ac76a,
__v: 0,
google: {},
twitter: {},
facebook: {},
local:
{ password: '$2a$08$9NGd0xNu0JbWMZ07ufyFRu8guwy147k8IBl5cAC4Y8APOuxreNI32',
email: '[email protected]' } }
How is this possible?
3) Where the control flow execution goes once done
method is executed?
Passport uses serializeUser function to persist user data (after successful authentication) into session. Function deserializeUser is used to retrieve user data from session.
Serializing a user determines which data of the user object should be stored in the session, usually the user id . The serializeUser() function sets an id as the cookie in the user's browser, and the deserializeUser() function uses the id to look up the user in the database and retrieve the user object with data.
Passport JS has over 500 authentication "Strategies" that can be used within a Node/Express app. Many of these strategies are highly specific (i.e. passport-amazon allows you to authenticate into your app via Amazon credentials), but they all work similar within your Express app.
After a long time of searching I found this article which explains authentication flow very clearly.
- When the user submits the login form, a POST request to /login is made resulting in the execution of the passport.authenticate middleware we've set up.
- As the authenticate middleware for that route is configured to handle the local strategy, passport will invoke our implementation of the local strategy.
- Passport takes the req.body.username and req.body.password and passes it to our verification function in the local strategy.
- Now we do our thing: loading the user from the database and checking if the password given matches the one in the database.
- If everything went fine and we want the user to login we invoke done(null, user).
- Calling done will make the flow jump back into passport.authenticate. It's passed the error, user and additional info object (if defined).
- If the user was passed, the middleware will call req.login (a passport function attached to the request).
- This will call our passport.serializeUser method we've defined earlier.
- Express loads the session data and attaches it to the req. As passport stores the serialised user in the session
- passport.session middleware is a Passport Strategy which will load the user object onto req.user if a serialised user object was found in the server.
- passport.initialize is invoked on the request, it finds the passport.user attached to the session. Next, passport.session is invoked.
- The passport.session middleware calls passport.deserializeUser we've setup. Attaching the loaded user object to the request as req.user.
I hope it helps.
Since you are using PassportJS so i assume you must be having some idea about how it works. So i would add further information which i think would clear your doubt.
Passport configuration involves three pieces:
The answer to your question lies in 3rd piece, sessions.
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.
According to your implementation only the user ID is serialized to the session, keeping the amount of data stored within the session small. When subsequent requests are received, this ID is used to find the user, which will be restored to req.user
In passports we are given option to write our own serialization and deserialization logic so that we can choose any appropriate database and not tied with strict rules.
So to summarise, after successful authentication, user object is serialised and stored in session, if you call req.user, then you would be able to retrieve the same user object.
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