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
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());
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);
}
));
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)));
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');
}
Β 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>
`);
});
Then, we handle authentication using Passport:
app.post('/login',
passport.authenticate('local', {
successRedirect: '/profile',
failureRedirect: '/login',
failureFlash: true
})
);
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>`);
});
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)
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?