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! πŸŽ‰

Heroku

Deploy with ease. Manage efficiently. Scale faster.

Leave the infrastructure headaches to us, while you focus on pushing boundaries, realizing your vision, and making a lasting impression on your users.

Get Started

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?

Image of DataStax

Langflow: Simplify AI Agent Building

Langflow is the easiest way to build and deploy AI-powered agents. Try it out for yourself and see why.

Get started for free

πŸ‘‹ Kindness is contagious

Engage with a wealth of insights in this thoughtful article, valued within the supportive DEV Community. Coders of every background are welcome to join in and add to our collective wisdom.

A sincere "thank you" often brightens someone’s day. Share your gratitude in the comments below!

On DEV, the act of sharing knowledge eases our journey and fortifies our community ties. Found value in this? A quick thank you to the author can make a significant impact.

Okay