Passport.js : Authentication - Local Strategy
1.Folder Structure
project-root/
│
├── config/ # Configuration files
│ ├── db-connection.js # Database connection setup
│ ├── passport-config.js # Passport.js configuration
│ ├── session-config.js # Session configuration
│ └── ... # Other configuration files
│
├── models/ # Mongoose models
│ ├── user.schema.js # User schema and model
│ └── ... # Other schemas and models
│
├── routes/ # Express route handlers
│ ├── auth.route.js # Authentication routes
│ ├── index.js # Index routes
│ └── users.js # User-related routes
│
├── views/ # EJS templates
│ ├── index.ejs # Main page template
│ ├── login.ejs # Login page template
│ ├── register.ejs # Registration page template
│ └── ... # Other view templates
│
├── .env # Environment variables
├── app.js # Main application file
└── package.json # Project metadata and dependencies
2. Install all these packages
Session and Flash Messaging:
npm install express-session connect-flash
Authentication:
npm install passport passport-local passport-local-mongoose
Database:
npm install mongoose
You can run these commands separately, or combine them into a single command for convenience:
npm install express-session connect-flash passport passport-local mongoose passport-local-mongoose
3. Add these codes to respective file
3.1 app.js
// 📂 app.js
require('dotenv').config({ path: "./.env" });
const createError = require('http-errors');
const express = require('express');
const path = require('path');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
// 🔷🔷🔷🔷🔷🔷🔷 Authentication Setup 🔷🔷🔷🔷🔷🔷🔷
const session = require('express-session');
const flash = require('connect-flash'); // Import connect-flash
const passport = require('./config/passport-config'); // Passport.js configuration
const authRouter = require('./routes/auth.route'); // Routes related to authentication
// Establish MongoDB connection and load user schema
require('./config/db-connection').connectDB();
require('./models/user.schema');
// 🔷🔷🔷🔷🔷🔷🔷 Authentication Setup End 🔷🔷🔷🔷🔷🔷🔷
const indexRouter = require('./routes/index');
const usersRouter = require('./routes/users');
const app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// 🔶🔶🔶🔶🔶🔶🔶 Session and Passport Setup 🔶🔶🔶🔶🔶🔶🔶
// Initialize session middleware for persistent login sessions
app.use(session({
secret: process.env.SESSION_SECRET || 'your-secret-key', // Replace with your secret
resave: false,
saveUninitialized: false,
cookie: { secure: false } // Set to true if using HTTPS
}));
// Initialize connect-flash
app.use(flash());
// Initialize Passport.js and restore authentication state from session
app.use(passport.initialize());
app.use(passport.session());
// Use authentication routes
app.use('/', authRouter);
// 🔶🔶🔶🔶🔶🔶🔶 Session and Passport Setup End 🔶🔶🔶🔶🔶🔶🔶
app.use('/', indexRouter);
app.use('/users', usersRouter);
// catch 404 and forward to error handler
app.use((req, res, next) => {
next(createError(404));
});
// error handler
app.use((err, req, res, next) => {
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
3.2 config/passport-config.js
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const User = require('../models/user.schema');
const loginFieldName = "email" || "username";
// Configure Passport.js to use the LocalStrategy
passport.use(new LocalStrategy(
{ usernameField: loginFieldName }, // Field used for login
async (loginFieldName, password, done) => {
try {
console.log("Testing -> 1");
// Find user by loginFieldName
const user = await User.findOne({
$or: [
{ username: loginFieldName },
{ email: loginFieldName }
]
});
console.log("user: ", user);
if (!user) {
console.log("Testing -> 2");
return done(null, false, { message: 'No user with that username' });
}
// Passport-local-mongoose handles password comparison
user.authenticate(password, (err, user, msg) => {
if (err) return done(err);
if (!user) return done(null, false, { message: msg });
return done(null, user);
});
} catch (err) {
return done(err);
}
}
));
// Serialize user into session
passport.serializeUser((user, done) => {
done(null, user.id);
});
// Deserialize user from session
passport.deserializeUser(async (id, done) => {
const user = await User.findById(id);
done(null, user);
});
module.exports = passport;
3.3 config/session-config.js
const session = require('express-session');
const sessionConfig = session({
secret: 'your-secret-key', // Secret key for session encryption
resave: false,
saveUninitialized: false,
cookie: { secure: false } // Set `secure: true` if using HTTPS
});
module.exports = sessionConfig;
3.4 routes/auth.route.js
const express = require('express');
const passport = require('../config/passport-config');
const User = require('../models/user.schema');
const router = express.Router();
const flash = require('connect-flash'); // Import connect-flash
const { isLoggedIn } = require('../middleware/isLoggedIn');
// Route to handle login with Passport.js authentication
router.post('/login', passport.authenticate('local', {
successRedirect: '/profile', // Redirect on successful login
failureRedirect: '/login', // Redirect on failed login
failureFlash: true // Enable flash messages for failures
}));
// Route to handle user logout
router.get('/logout', (req, res) => {
if (!req.isAuthenticated()) {
// If the user is not authenticated, respond with an error message
return res.status(400).send('You are not logged in');
}
// Proceed with logging out
req.logout((err) => {
if (err) {
return next(err);
}
res.send('Logout Successfully');
// res.redirect('/');
});
});
router.post('/register', async (req, res, next) => {
console.log(req.body)
try {
const { username, email, password } = req.body;
const encryptedDetail = password;
await User.register(new User({ username, email }), encryptedDetail);
res.send("Registered Success")
// res.redirect("/login");
} catch (err) {
console.error("Error: ", err);
res.send(err.message);
}
})
module.exports = router;
3.5 /middleware/isLoggedIn.js
// const isLoggedIn = (req, res, next) => {
exports.isLoggedIn = (req, res, next) => {
if (req.isAuthenticated()) {
return next();
} else {
res.redirect("/login");
}
}
// module.exports = isLoggedIn;
// isko dusre page mein fetch krne ke liye - destructuring krne ki jarrort nhi hai
3.6 /models/user.schema.js
// Import the mongoose library
const mongoose = require('mongoose');
// Import passport-local-mongoose plugin
const plm = require('passport-local-mongoose');
// Define a new schema for the user collection
const user_schema = mongoose.Schema({
email: {
type: String,
required: true
},
username: {
type: String,
required: true // Field is required
},
password: String, // Password field as a string
}, { timestamps: true } // Automatically adds createdAt and updatedAt timestamps
);
// Apply the passport-local-mongoose plugin to the schema
// Configured to use 'email' as the field for login instead of the default 'username'
// user_schema.plugin(plm);
user_schema.plugin(plm, { usernameField: 'email' }); // ⭐⭐⭐
// Create a model named "social-media" using the user schema
const User = mongoose.model("User", user_schema);
// Log a message indicating the schema has been created
console.log("Schema Created");
// Export the user collection model
module.exports = User;
3.7 /routes/index.route.js (Optional - Create yourself)
var express = require('express');
const { isLoggedIn } = require('../middleware/isLoggedIn');
var router = express.Router();
/* GET home page. */
router.get('/', function (req, res, next) {
res.render('index', { title: 'Express' });
});
router.get('/register', (req, res, next) => {
res.render('register', { error_messages: req.flash('error') });
})
router.get('/login', function (req, res, next) {
res.send("Login Page");;
});
// Profile route
router.get('/profile', isLoggedIn, (req, res) => {
// res.render('profile', { user: req.user });
res.send('profile Page');
});
module.exports = router;
4. API Documentation
Endpoints
Login
POST
/login
Body:
{ "email": "
user@example.com
", "password": "yourpassword" }
Success:
{ "token": "jwt-token" }
Error:
{ "message": "Invalid credentials" }
Register
POST
/register
Body:
{ "email": "
user@example.com
", "username": "username", "password": "yourpassword" }
Success:
{ "message": "User registered" }
Error:
{ "message": "Validation error" }
Profile
GET
/profile
Header:
Authorization: Bearer <token>
Success:
{ "email": "
user@example.com
", "username": "username" }
Error:
{ "message": "Not authenticated" }
Logout
GET
/logout
Header:
Authorization: Bearer <token>
Success:
{ "message": "Logged out" }
Error:
{ "message": "Not authenticated" }
Errors
400: Bad Request
401: Unauthorized
403: Forbidden
404: Not Found
500: Server Error
Subscribe to my newsletter
Read articles from Ayush Kumar directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Ayush Kumar
Ayush Kumar
A passionate MERN Stack Developer from India I am a full stack web developer with experience in building responsive websites and applications using JavaScript frameworks like ReactJS, NodeJs, Express etc.,