Login Authentication with Express and Passport
Instead of having to use json web tokens for authentication there had to be a simpler way to handle authentication for small applications . Token authentication is better for large applications with multiple databases. For small applications with one database, session-based authentication is a simpler approach to implement and test.
Step 1: Start The Express Server
const express = require('express');
const session = require('express-session');
const passport = require('passport');
const MongoStore = require('connect-mongo');
const mongoose = require('mongoose');
require('dotenv').config();
const app = express();
app.use(express.json()); // Parse incoming JSON
Step 2: Configure Sessions with express-session and MongoDB
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
store: MongoStore.create({
mongoUrl: process.env.MONGO_URI,
collectionName: 'sessions'
}),
cookie: { // Set cookie
maxAge: 1000 * 60 * 60 * 24, // 24 hours
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax'
}
}));
Step 3: Initialize Passport
app.use(passport.initialize()); app.use(passport.session()); // Enables persistent login sessions
Step 4: Configure Passport Serialization
Passport determines what user data to store in the session using serializeUser(), and how to retrieve the user with deserializeUser().
const User = require('./models/User'); // Adjust path to your user model
passport.serializeUser((user, done) => {
done(null, user.id); // Store only the user ID in the session
});
passport.deserializeUser(async (id, done) => {
try {
const user = await User.findById(id);
done(null, user); // Adds user object to req.user
} catch (err) {
done(err, null);
}
});
If you want to store additional info (like auth type, timestamps, etc.), you can serialize an object instead of just user.id.
Storing data to session object:
Step 5: Create a Session After Login
Here’s a sample route to manually create a session — for example, after a user logs in via a custom frontend:
const express = require('express');
const router = express.Router();
const User = require('../models/User');
router.post('/create-session', async (req, res) => {
const { isLoggedIn, userId } = req.body;
try {
if (!isLoggedIn) {
return res.status(400).json({ success: false, error: 'User is not logged in.' });
}
const user = await User.findById(userId);
if (!user) {
return res.status(404).json({ success: false, error: 'User not found.' });
}
req.login(user, (err) => {
if (err) {
return res.status(500).json({ success: false, error: 'Failed to create session.' });
}
return res.json({ success: true });
});
} catch (error) {
console.error(error);
res.status(500).json({ success: false, error: 'A server error has occurred.' });
}
});
module.exports = router;
***Note***: In most real-world applications, you'd authenticate the user with credentials first (e.g., with Passport's local strategy), then call req.login() upon successful authentication.
Step 6: Checking if a User is Authenticated
Use Passport's req.isAuthenticated() method to protect routes:
app.get('/', (req, res) => {
if (req.isAuthenticated()) {
res.sendFile(path.join(__dirname, 'public/views/index.html'));
} else {
res.sendFile(path.join(__dirname, 'public/views/auth/index.html'));
}
});
You can also write middleware:
function ensureAuth(req, res, next) {
if (req.isAuthenticated()) {
return next();
}
res.redirect('/login');
}
When to Use Session-Based Auth
Use session-based authentication when:
- You control both frontend and backend (monolithic apps).
- Your backend is centralized and doesn't need to be stateless.
- You want to avoid managing token expiration, refresh logic, and extra database lookups for token validation.
thanks for your input @kitsVA