Even if you're already familiar with the process of cookies being saved to a web browser, the overall process can often become a bit lengthy and confusing to follow, especially when combined with third party access delegation. Now, obviously, if you aren't a developer then none of this would matter to you, but if you are, there's definitely a lot of useful information to know about this process—even if you aren't directly working with authentication.
While cookies have many purposes, the purpose that I'll be talking about, as I have implied, is quick and seamless authentication. I'm sure you've encountered it countless times with websites, especially with social networking websites like Facebook, Twitter, YouTube, and so on. You log in once, and each time you come back after you're already signed in.
Conceptually, you could think of this process as very similar to a coat check or a valet. Once you leave your car with the valet, they need some uniquely identifying piece of information to give you that they will quickly be able to associate with your car the next time you come back and show it to them, so that they know what to give you.
Likewise, when you first log in to your account on a website, a cookie is generated on the server and sent back to your browser, and your browser stores that cookie. When you inevitably leave that website, the next time you come back, your browser will present the cookie this website gave it. The server for this website will then find the account it associated with this cookie and send it back to your browser.
In addition to the convenience this provides to the user, it also makes it much easier for the server to keep track of each user. With the user data being injected into every request as it is received by the server, the server can then carry out said requests specific to the user who is requesting it.
Now let's take a look at an example of this process from a Node server using Express, Passport, and Google OAuth.
passport.use(new GoogleStrategy({
clientID: OAUTH_CLIENT_ID,
clientSecret: CLIENT_SECRET,
callbackURL: '/auth/google/redirect',
},
(async (accessToken, refreshToken, profile, done) => {
const { familyName, givenName } = profile.name;
let user = await User.findOne({ where: { id: profile.id } });
if (!user) {
user = await User.create({
first_name: givenName,
last_name: familyName,
email: profile.emails[0].value,
photo: profile.photos[0].value,
});
}
done(null, user);
})));
Above is an instance of Passport being used on a server to authenticate with Google to sign up users. During the initial sign up process after being redirected back to the original website from the Google Sign in page, the asynchronous callback function seen in the second half of the above code snippet is fired. In that function, you can see it first checks to see if the a user already exists in its connected database using the information it got from Google. If the user does not exist, it will create an account using that information.
After creating an entry for the user in its connected database, the server will then take a uniquely identifying piece of information from that and create a cookie to send back to the browser. This is like the valet giving you a ticket to show them the next time you come back, only a little more complicated. Since it would be too easy for someone else to falsify or guess this information, Passport, and other services like it, will use a form of encryption to scramble this information before sending it back. That's where Passport's serializeUser()
method comes in.
passport.serializeUser((user, done) => {
done(null, user.googleId);
});
This method performs the aforementioned encryption before passing the cookie along to be sent back to the browser. In the above example, the user's Google ID is being used as the uniquely identifying information.
Finally, as you may expect, there is an accompanying deserializeUser()
user method to reverse this process and look up the user's account the next time the browser makes a request with that cookie, which looks a little something like this:
passport.deserializeUser(async (googleId, done) => {
const user = await User.findOne({ where: { googleId } });
done(null, user);
});
Conclusion
I've really only touched the surface of the entire overall process, but this should give you a little better of an understanding of how it works. Authentication is an absolutely essential part of any web application, and cookies can make that process into a seamless experience for users, as well as the developers. For a full tutorial and explanation of all the pieces working together, I would highly recommend checking out this YouTube playlist: https://www.youtube.com/playlist?list=PL4cUxeGkcC9jdm7QX143aMLAqyM-jTZ2x
**Be sure to reference the docs here: http://www.passportjs.org/docs/google/ when setting up the boiler plate code and installing the modules, as some of the specifics for that in the videos seem to be a bit outdated.
Top comments (0)