Authentication with Google OAuth
Authentication with Google OAuth

These are my notes for Stephen Grider’s Node with React course on Udemy: https://www.udemy.com/course/node-with-react-fullstack-web-development/
Using PassportJS
PassportJS will help us with a large chunk of the Googe OAuth process. When the user clicks ‘Login,’ Passport kicks in and forwards the request to Google. Google prompts the user for permission, and then kicks back a code (in the form of a query string) to our server. Our server then uses that code to request certain information about the user from Google.
Passport has a couple of downsides. First, we have to supply Passport with a few bits of code at specific intervals during that long flow. We as developers are left in the dark and may feel like we are writing disconnected and nebulous bits code. Second, we have to keep in mind that we’ll need to install at least two packages: Passport, which contains the general helper functions for Express, and also one more passport strategies, each of which contains functionality specific to one login strategy (e.g. Google, Facebook, email/password).
In this example, we’re only concerned with Google OAuth. We’ll require both Passport and Passport-Google-OAuth2.0, and then instruct Passport to use a new instance of the Google strategy:
URI Setting
The next step involves getting credentials from console.developers.google.com. We’ll provide our app’s name for the consent screen, receive a client ID and a client secret. We’ll also be prompted to enter an authorized redirect URI. What is this URI and why do we need it? When the user signs in through the Google consent screen, Google needs to send the user’s profile back to a specific endpoint. Of course, this needs to be our endpoint, lest some hacker try to make Google OAuth send user information to some malicious destination. So, we’ll set our own endpoint, which Google then will store on its servers. Every time a user goes through the Google OAuth flow, it’ll check that the callback URL is the same as the redirect URI.
Note: we’ll discuss the second argument in a moment.
Now we can write a couple of handlers. The first is for when a user initially visits our Google authentication endpoint to sign in, and the second handles what Google will do when it hits the URI we specified. Luckily, we can use passport.authenticate
for both:
The string "google"
comes from the internal implementation of the Google strategy. Now we have the Passport side of our authentication completed!The next step is to store this user in our database and write logic that will actually log the user in to our application.
Persisting the User in a Database
I’ve gone over in detail how to get started with MongoDB in another article, so I’ll skip over it here. Suffice to say, we’ll connect to a new database with Mongoose and create a user schema. Then, in that same callback function that took accessToken
as an argument earlier, we’ll save
a new instance of the user model with a googleId
property equal to the id
in the profile Google gives us:
Now any user that goes through our OAuth flow will be persisted in our database! However, this code has two problems. First, there’s no check to see if the user already exists in our database. Also, right now our OAuth flow gets stuck in limbo because we haven’t called the done()
function yet. The done()
function will take two arguments: an error ( null
in this case) and the user returned by the promise.
Creating a Cookie
Passport has a method called serializeUser()
which will automatically create a cookie for us:
If serialization is the process of creating a cookie, then deserialization is the process of extracting an ID from a cookie and returning the corresponding user from the database:
Of course, we have to tell our Express app that we want it to use cookies. We’ll install a package called cookie-session and then call it inside app.use()
. The cookie session function itself takes an options object as an argument. Note that keys
(analogous to a JWT secret) is an array because we have the ability to set more than one key. Below that, we just call a couple more Passport methods:
A quick explanation of how this all works together: when a request comes in, cookie-session extracts the cookie data. Then, Passport extracts the user ID from that data. Finally, our deserializeUser
function turns that ID into a full-fledged instance of our user model, which then gets add to the request as req.user
. We can test to see if this is all working by creating a simple endpoint:
Logging Out and Redirects
Well, you’ve made it this far! Thankfully, logging out is straightforward:
We have our login and logout routes handled, but right now, from a UI standpoint, nothing seems to happen. In fact, our login route still gives us a nasty error message, something like cannot GET auth/google/callback
. We’ll add another middleware that’ll redirect the user to their dashboard when they log in:
We’ll add another redirect for logout (replacing the part where we send the empty user object in the response — that was just for testing).
Nhận xét
Đăng nhận xét