DEV Community

Shreelaxmi Hegde
Shreelaxmi Hegde

Posted on

Auth Series #5: Authorization implementation with Passport.js

We have covered Cookies and Sessions in the previous part.
Now, it’s time to use them in our authorization flow.

As discussed earlier, authorization means allowing access to specific parts or actions that a user is permitted to perform.
Before we authorize a user, we first need to authenticate them (verify their identity).

We’ve already handled authentication.
Now, our next goal is to remember the authenticated user across sessions. And that’s where cookies and sessions come into play.


⚙️ Session Setup

After installing and importing express-session, the next step is to configure our session options:

const sessionOptions = {
    secret: "secretecode",
    resave: false,
    saveUninitialized: true,
    cookie: {
        httpOnly: true, // prevents client-side JavaScript access for better security
    }
}

app.use(session(sessionOptions)); //setup express-session middleware
Enter fullscreen mode Exit fullscreen mode

📌 What does this code snippet do?
secret: Used to sign the session ID cookie to prevent tampering.

resave: false: Ensures the session isn’t saved back to the store if it hasn’t been modified.

saveUninitialized: true: Saves new sessions that haven’t been modified yet.

cookie.httpOnly: Helps protect against XSS attacks by making cookies inaccessible via client-side JavaScript.

In short, this middleware automatically attaches a session object to every request (req.session), allowing us to store and retrieve user-specific data securely on the server. These are the common parameters defined while creating session.


🔐 Passport Setup

Once the session is configured, we can connect it with Passport.js, which handles authentication seamlessly.

app.use(passport.session()); // Connect Passport with session
Enter fullscreen mode Exit fullscreen mode

This line ensures that Passport can store and access user data within the existing session.

📌 Why do we connecting Passport to session?
When a user logs in successfully, Passport authenticates them only for that single HTTP request.
Since HTTP is a stateless protocol, the server doesn’t automatically remember the user between different requests.

By connecting Passport to the session, we enable it to store the user’s identity in a session (on the server) and keep them logged in across multiple pages or browser refreshes without needing to log in again each time.


We have successfully connected Passport with express-session. But there are two more crucial steps to complete the flow: serializeUser() and deserializeUser().

📌 Why do we need them?

When a user logs in, a session is created and attached to all future requests from the browser.

⤷ However, when a request reaches the server, it only contains the session ID. This means the server sees some “unknown ID” but doesn’t yet know which user it belongs to.

serializeUser() solves this problem by telling Passport what user information to store in the session (usually the user ID), effectively linking the session ID to a specific user.

⤷ On every subsequent request after login, deserializeUser() runs. It fetches the full user information from the database using the ID stored in the session.

⤷ This ensures that req.user is populated, so you can access the authenticated user’s details in any route or middleware.

Usage :

passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
Enter fullscreen mode Exit fullscreen mode

📌 Passport Session Flow: Serialize & Deserialize

User logs in
     │
     ▼
Passport authenticates credentials
     │
     ▼
serializeUser() runs
     │
     │  Stores only the user ID in the session
     ▼
Session created and sessionID sent to browser as cookie
     │
     ▼
Browser makes another request
     │
     ▼
Session middleware reads sessionID from cookie
     │
     ▼
deserializeUser() runs
     │
     │  Uses stored user ID to fetch full user info from DB
     ▼
req.user is populated → available in all route handlers

Enter fullscreen mode Exit fullscreen mode

These are common practices to implement an Authorization system.
Now, let’s see how we can use them in our routes to authorize actions like edit, delete, etc.

Example Scenario: Blog Application
In our blog app, users can create, edit, delete, or update their posts.

We have already completed the authentication steps.
Now, our goal is to allow users to perform actions only on their own posts. for example, the author of a post can edit or delete it, but others cannot.

Step 1: Define Middleware
We first create a middleware function to check the user’s role or ownership:

function isAuthor(req, res, next) {
  if (req.user && req.user.role === 'author') {
    return next();
  }
  res.status(403).send('Access Denied');
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Apply Authorization in Routes
Use the middleware in your route definitions:

app.delete('/posts/:id', isAuthor, deletePost); 
Enter fullscreen mode Exit fullscreen mode

How it works internally:
⤷ When a user tries to delete a post, the request hits the route handler.
⤷ The isAuthor middleware runs first.
⤷ req.user (fetched via deserializeUser()) is checked against the required role.
⤷ If authorized, the request proceeds to deletePost. Otherwise, access is denied.

You can implement similar middleware for all other routes that require authorization.


This completes our blog series on Authentication and Authorization in Express.js.

I hope you enjoyed this series and gained a deeper understanding of the under-the-hood workflow behind authentication and authorization.

Thank you for reading! 🎉

Top comments (2)

Collapse
 
roshan_sharma_7deae5e0742 profile image
roshan sharma

Awesome breakdown! I love how you explained the Passport session flow so clearly. Did you run into any tricky edge cases while implementing it in your blog app?

Collapse
 
shreelaxmihegde profile image
Shreelaxmi Hegde

Thanks a lot 😊.
Yeah, a bit. especially around keeping the session alive after login. Took a while to figure out the right middleware order 😅