DEV Community

A0mineTV
A0mineTV

Posted on

A Comprehensive Guide to Local Authentication with Passport.js in Express

A Comprehensive Guide to Local Authentication with Passport.js in Express

Authentication is a fundamental aspect of web applications, enabling secure user access and personalized experiences. In this guide, we’ll walk through the complete setup of local authentication in a Node.js and Express application using Passport.js.

📌 What is Passport.js?

Passport.js is a flexible and modular authentication middleware for Node.js. It supports multiple authentication strategies, including local authentication (username/password), OAuth providers (Google, Facebook), and even JWT authentication.

🚀 Setting Up the Express Server

Before we begin, ensure you have Node.js installed. You can check this by running:

node -v

1️⃣ Install Dependencies

Run the following command to install the required packages:

npm init -y  # Initialize a Node.js project
npm install express passport passport-local express-session connect-flash
Enter fullscreen mode Exit fullscreen mode
  • express: Web framework for Node.js

  • passport: Authentication middleware

  • passport-local: Strategy for username/password authentication

  • express-session: Session management for authentication

  • connect-flash: Flash messages for displaying login errors

2️⃣ Create the Server (server.js)

const express = require('express');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const session = require('express-session');
const flash = require('connect-flash');

const users = [
    { id: 1, username: 'alice', password: 'secret', role: 'admin' },
    { id: 2, username: 'bob', password: 'password', role: 'user' }
];

const findUser = (username) => users.find(user => user.username === username);

const app = express();

// Middleware Configuration
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(session({
    secret: 'supersecretkey',
    resave: false,
    saveUninitialized: false
}));
app.use(flash());
app.use(passport.initialize());
app.use(passport.session());
Enter fullscreen mode Exit fullscreen mode

3️⃣ Configure Passport Local Strategy

Passport needs to be set up with a strategy for authenticating users. The LocalStrategy validates the username and password:

passport.use(new LocalStrategy(
    (username, password, done) => {
        const user = findUser(username);
        if (!user) return done(null, false, { message: 'User not found' });
        if (password !== user.password) return done(null, false, { message: 'Incorrect password' });
        return done(null, user);
    }
));
Enter fullscreen mode Exit fullscreen mode
  • findUser(username): Searches for a user in the database (mocked with an array).

  • done(null, false, { message }): Sends error messages when authentication fails.

4️⃣ Serialize and Deserialize User Sessions

To maintain authentication across requests, Passport serializes user information into a session and deserializes it upon subsequent requests:

passport.serializeUser((user, done) => done(null, user.id));
passport.deserializeUser((id, done) => done(null, users.find(user => user.id === id)));
Enter fullscreen mode Exit fullscreen mode

5️⃣ Middleware to Protect Routes

To prevent unauthorized access, we create a middleware function to check if a user is authenticated:

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

 6️⃣ Define Routes for Login and Authentication

We create a login page where users can input their credentials:

app.get('/login', (req, res) => {
    const errorMessage = req.flash('error');
    res.send(`
        <h2>Login</h2>
        ${errorMessage.length ? `<p style="color: red;">${errorMessage[0]}</p>` : ''}
        <form method="post" action="/login">
            <div><label>Username:</label> <input type="text" name="username"/></div>
            <div><label>Password:</label> <input type="password" name="password"/></div>
            <button type="submit">Login</button>
        </form>
    `);
});
Enter fullscreen mode Exit fullscreen mode

Then, we handle authentication using Passport:

app.post('/login',
    passport.authenticate('local', {
        successRedirect: '/profile',
        failureRedirect: '/login',
        failureFlash: true
    })
);
Enter fullscreen mode Exit fullscreen mode

7️⃣ Protect Profile Route

The /profile route should be accessible only to logged-in users:

app.get('/profile', ensureAuthenticated, (req, res) => {
    res.send(`<h2>Welcome, ${req.user.username}!</h2>`);
});
Enter fullscreen mode Exit fullscreen mode

8️⃣ Start the Server

Finally, start the server:

app.listen(3000, () => console.log('Server running on http://localhost:3000'));

🔥 How It Works

  • User visits /login and enters credentials.

  • Passport.js checks credentials using the LocalStrategy.

  • If successful, the user is redirected to /profile.

  • If authentication fails, an error message is shown.

  • Authenticated users can access the protected /profile route.

🎯 Conclusion

By following these steps, we have successfully implemented local authentication using Passport.js in an Express.js application. This setup provides a secure and scalable foundation for handling user authentication.

🚀 What’s next? Try adding Google OAuth authentication to your project! Let me know in the comments if you want a tutorial on that. Happy coding! 🎉

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

Top comments (1)

Collapse
 
dariomannu profile image
Dario Mannu

Nice intro. I recently implemented a full-stack passport.js demo on Stackblitz, so easy to share and build further, but slighly more focused on the front-end and reactive streams.

OAuth sounds like a great next step, actually... time to make OAuth simple to add everywhere, isn't it? Collab?

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay