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