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

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?