Build a Login System in NodeJS with Passport.js Authentication

I’m excited to share a recent project that I successfully completed: developing a login page with authentication using Passport.js in NodeJS. This project not only enhances security but also improves the user experience by providing a seamless and reliable way to manage user logins.

When working on web applications, user authentication is one of the most critical components. Passport.js is a popular middleware for Node.js that simplifies the process of implementing authentication. It supports a wide range of strategies, including local authentication, OAuth, and even social logins like Google or Facebook. For this project, I chose Passport.js for its flexibility and community support.

Setting Up the Project

First, I created a new Node.js application. Here are the key steps:

  1. Initialize the Project:mkdir passport-auth-project cd passport-auth-project npm init -y
  2. Install Required Packages: I installed Express, Passport, and other necessary packages:npm install express passport passport-local express-session bcryptjs body-parser

Creating the Login Page

I designed a simple login page using HTML and CSS. Here’s a snippet of the login form:

<form action="/login" method="POST">
  <label for="username">Username:</label>
  <input type="text" id="username" name="username" required />

  <label for="password">Password:</label>
  <input type="password" id="password" name="password" required />

  <button type="submit">Login</button>
</form>

This form sends the username and password to the /login route, which I handled in the server code.

Server-Side Implementation

Express App Setup:

I started by setting up the basic Express app:

const express = require('express');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const session = require('express-session');
const bcrypt = require('bcryptjs');

const app = express();
app.use(express.urlencoded({ extended: false }));
app.use(session({ secret: 'secret', resave: false, saveUninitialized: false }));
app.use(passport.initialize());
app.use(passport.session());

const users = []; // Temporary user storage

Passport Local Strategy:

I configured Passport.js to use the passport-local strategy for authentication:

passport.use(
  new LocalStrategy((username, password, done) => {
    const user = users.find((u) => u.username === username);
    if (!user) {
      return done(null, false, { message: 'Incorrect username.' });
    }

    bcrypt.compare(password, user.password, (err, isMatch) => {
      if (err) throw err;
      if (isMatch) {
        return done(null, user);
      } else {
        return done(null, false, { message: 'Incorrect password.' });
      }
    });
  })
);

passport.serializeUser((user, done) => {
  done(null, user.username);
});

passport.deserializeUser((username, done) => {
  const user = users.find((u) => u.username === username);
  done(null, user);
});

Register and Login Routes:

app.post('/register', (req, res) => {
  const { username, password } = req.body;
  const hashedPassword = bcrypt.hashSync(password, 10);
  users.push({ username, password: hashedPassword });
  res.redirect('/login');
});

app.post('/login',
  passport.authenticate('local', {
    successRedirect: '/dashboard',
    failureRedirect: '/login',
  })
);

Protected Route:

To ensure only authenticated users can access certain pages:

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

app.get('/dashboard', ensureAuthenticated, (req, res) => {
  res.send('Welcome to your dashboard!');
});

Testing the Application

To test the application, I ran the server:

node app.js

Then, I visited http://localhost:3000 to access the login page. After registering a user, I tested the login functionality, ensuring it redirected correctly and handled incorrect credentials gracefully.

Final Thoughts

This project was an exciting journey into the world of authentication in Node.js. Using Passport.js, I could implement a robust login system with minimal effort. The modular design of Passport.js makes it easy to extend this system in the future, for example, by adding OAuth strategies or integrating a database for user management.

If you’re working on a similar project or have any questions, feel free to reach out or share your experiences. Let’s build secure and user-friendly applications together!

Related blog posts