Published on

User Authentication with Passport.js in Express.js: A Comprehensive Guide with Examples

Authors

Passport.js is a popular authentication middleware for Express.js that simplifies the process of implementing user authentication in web applications. It provides a modular approach and supports various authentication strategies, including local, OAuth, and JWT. In this comprehensive guide, we will explore how to use Passport.js to implement user authentication in Express.js with practical examples.

Understanding Passport.js

Passport.js is an authentication middleware for Node.js and Express.js. It provides a set of flexible and modular authentication strategies that can be easily integrated into an Express.js application. Passport.js follows a "strategy" pattern, where each authentication strategy handles a specific method of authentication, such as username/password, social login, or JSON Web Tokens (JWT).

Example: Implementing Local Authentication with Passport.js

Let's start by looking at an example of implementing local authentication using Passport.js. Local authentication involves authenticating users based on a username and password combination stored in the application's database. Here's a step-by-step guide:

  1. Install Dependencies : Begin by installing the necessary dependencies. Run the following command in your Express.js project directory:

npm install passport passport-local
  1. Configure Passport.js : Set up Passport.js in your Express.js application by requiring the necessary modules and configuring the local strategy:
// app.js

const express = require('express')
const passport = require('passport')
const LocalStrategy = require('passport-local').Strategy

// Configure Passport.js
passport.use(
  new LocalStrategy((username, password, done) => {
    // Implement your own logic to verify the username and password
    User.findOne({ username }, (err, user) => {
      if (err) {
        return done(err)
      }
      if (!user) {
        return done(null, false, { message: 'Incorrect username.' })
      }
      if (!user.validPassword(password)) {
        return done(null, false, { message: 'Incorrect password.' })
      }
      return done(null, user)
    })
  })
)

// ...

In the example above, we configure the local strategy by providing a callback function that verifies the username and password. You need to implement your own logic to query the database and validate the user's credentials.

  1. Implement Login Route : Create a route in your Express.js application to handle the login form submission and authenticate the user using Passport.js:
// app.js

app.post(
  '/login',
  passport.authenticate('local', { successRedirect: '/', failureRedirect: '/login' })
)
  1. Protect Routes : Protect routes that require authentication by applying the ensureAuthenticated middleware. If a user is not authenticated, redirect them to the login page:
// app.js

function ensureAuthenticated(req, res, next) {
  if (req.isAuthenticated()) {
    return next()
  }
  res.redirect('/login')
}

app.get('/dashboard', ensureAuthenticated, (req, res) => {
  res.render('dashboard')
})

In this example, the ensureAuthenticated middleware checks if the user is authenticated using req.isAuthenticated(). If the user is authenticated, the next middleware or route handler is called. Otherwise, the user is redirected to the login page.

Example: Implementing OAuth Authentication with Passport.js

OAuth authentication allows users to log in using their existing accounts on external services like Google, Facebook, or Twitter. Passport.js provides strategies for various OAuth providers. Here's an example of implementing OAuth authentication using Passport.js:

  1. Install Dependencies : Install the necessary Passport.js strategies for the desired OAuth provider. For example, to implement Google OAuth, run the following command:

npm install passport-google-oauth
  1. Configure Passport.js : Configure Passport.js with the desired OAuth strategy by providing the necessary client ID, client secret, and callback URL:
// app.js

const passport = require('passport')
const GoogleStrategy = require('passport-google-oauth').OAuth2Strategy

// Configure Passport.js
passport.use(
  new GoogleStrategy(
    {
      clientID: 'YOUR_CLIENT_ID',
      clientSecret: 'YOUR_CLIENT_SECRET',
      callbackURL: 'http://localhost:3000/auth/google/callback',
    },
    (accessToken, refreshToken, profile, done) => {
      // Implement your own logic to handle the user profile returned by Google
      User.findOrCreate({ googleId: profile.id }, (err, user) => {
        return done(err, user)
      })
    }
  )
)

// ...

In the example above, we configure the Google OAuth strategy by providing the client ID, client secret, and callback URL. You will need to register your application with the OAuth provider to obtain the client ID and client secret.

  1. Implement Authentication Routes : Create routes in your Express.js application to handle the authentication flow, including the route for initiating the OAuth authentication process and the callback route for handling the OAuth provider's response:
// app.js

app.get('/auth/google', passport.authenticate('google', { scope: ['profile'] }))

app.get(
  '/auth/google/callback',
  passport.authenticate('google', { successRedirect: '/', failureRedirect: '/login' })
)

In this example, the user is redirected to the Google authentication page when accessing the /auth/google route. After successful authentication, the user is redirected to the callback URL specified in the configuration.

Example: Implementing JWT Authentication with Passport.js

JSON Web Tokens (JWT) provide a stateless authentication mechanism that allows clients to authenticate using a token. Passport.js can be used to implement JWT authentication in Express.js applications. Here's an example:

  1. Install Dependencies : Install the necessary Passport.js strategy for JWT authentication. Run the following command:

npm install passport-jwt
  1. Configure Passport.js : Configure Passport.js to use the JWT strategy by providing a secret key and a verification callback:
// app.js

const passport = require('passport')
const JwtStrategy = require('passport-jwt').Strategy
const ExtractJwt = require('passport-jwt').ExtractJwt

// Configure Passport.js
passport.use(
  new JwtStrategy(
    {
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      secretOrKey: 'YOUR_SECRET_KEY',
    },
    (payload, done) => {
      // Implement your own logic to find the user based on the payload
      User.findById(payload.sub, (err, user) => {
        if (err) {
          return done(err, false)
        }
        if (user) {
          return done(null, user)
        } else {
          return done(null, false)
        }
      })
    }
  )
)

// ...

In the example above, we configure the JWT strategy by providing a secret key and a verification callback. The verification callback is responsible for finding the user based on the payload of the JWT.

  1. Protect Routes : Protect routes that require JWT authentication by applying the passport.authenticate('jwt') middleware:
// app.js

app.get('/api/protected', passport.authenticate('jwt', { session: false }), (req, res) => {
  res.json({ message: 'Protected API endpoint' })
})

In this example, the /api/protected route is protected using the passport.authenticate('jwt') middleware. If the JWT is valid and the user is authenticated, the next middleware or route handler is called.

Conclusion

Passport.js is a powerful authentication middleware that simplifies user authentication in Express.js applications. By using Passport.js and its various authentication strategies, you can implement local, OAuth, or JWT authentication with ease. In this comprehensive guide, we covered practical examples of implementing local, OAuth, and JWT authentication using Passport.js. With this knowledge, you can now secure your Express.js applications and provide a seamless authentication experience to your users.