Kritim Yantra
Jul 31, 2025
Welcome, Future Full-Stack Hero!
Ever wondered how Instagram remembers you? Or how an app knows you’ve logged in?
Well, it's all about authentication — and today, you’re going to learn how to build your own login, logout, and register system using Express.js, the most popular backend framework in the Node.js ecosystem. 🚀
Whether you're new to backend development or polishing your portfolio for job interviews, this project is practical, modern, and beginner-friendly.
✅ A user registration form
✅ A login page that validates credentials
✅ Secure password storage with bcrypt
✅ Session-based authentication
✅ A logout system that ends the session
✅ Bonus: Flash messages for errors and success
💡 Note: You can use any database or frontend, but this tutorial keeps things simple and clean.
mkdir express-auth-app
cd express-auth-app
npm init -y
npm install express mongoose bcryptjs express-session connect-flash ejs body-parser
express-auth-app/
│
├── models/
│ └── User.js
├── views/
│ ├── login.ejs
│ ├── register.ejs
│ └── dashboard.ejs
├── routes/
│ └── auth.js
├── app.js
└── .env
User
Modelmodels/User.js
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
username: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
}
});
module.exports = mongoose.model('User', UserSchema);
app.js
const express = require('express');
const mongoose = require('mongoose');
const session = require('express-session');
const flash = require('connect-flash');
const bodyParser = require('body-parser');
const authRoutes = require('./routes/auth');
const app = express();
// Connect to MongoDB
mongoose.connect('mongodb://localhost:27017/auth2025', {
useNewUrlParser: true,
useUnifiedTopology: true
}).then(() => console.log("MongoDB connected"))
.catch(err => console.log(err));
// Middleware
app.set('view engine', 'ejs');
app.use(express.static('public'));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(session({
secret: 'secretkey2025',
resave: false,
saveUninitialized: true
}));
app.use(flash());
// Global flash variables
app.use((req, res, next) => {
res.locals.success_msg = req.flash('success_msg');
res.locals.error_msg = req.flash('error_msg');
next();
});
// Routes
app.use('/', authRoutes);
const PORT = 5000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
routes/auth.js
const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const User = require('../models/User');
// Register Page
router.get('/register', (req, res) => res.render('register'));
// Register Handle
router.post('/register', async (req, res) => {
const { username, password, password2 } = req.body;
let errors = [];
if (!username || !password || !password2) {
errors.push({ msg: 'Please enter all fields' });
}
if (password !== password2) {
errors.push({ msg: 'Passwords do not match' });
}
if (password.length < 6) {
errors.push({ msg: 'Password must be at least 6 characters' });
}
if (errors.length > 0) {
return res.render('register', { errors });
}
const existingUser = await User.findOne({ username });
if (existingUser) {
req.flash('error_msg', 'Username already exists');
return res.redirect('/register');
}
const newUser = new User({ username, password });
const salt = await bcrypt.genSalt(10);
newUser.password = await bcrypt.hash(password, salt);
await newUser.save();
req.flash('success_msg', 'You are now registered and can log in');
res.redirect('/login');
});
// Login Page
router.get('/login', (req, res) => res.render('login'));
// Login Handle
router.post('/login', async (req, res) => {
const { username, password } = req.body;
const user = await User.findOne({ username });
if (!user) {
req.flash('error_msg', 'Invalid credentials');
return res.redirect('/login');
}
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
req.flash('error_msg', 'Invalid credentials');
return res.redirect('/login');
}
req.session.user = user;
req.flash('success_msg', 'You are now logged in');
res.redirect('/dashboard');
});
// Dashboard
router.get('/dashboard', (req, res) => {
if (!req.session.user) {
req.flash('error_msg', 'Please log in to view this page');
return res.redirect('/login');
}
res.render('dashboard', { user: req.session.user });
});
// Logout
router.get('/logout', (req, res) => {
req.session.destroy(err => {
if (err) console.log(err);
res.redirect('/login');
});
});
module.exports = router;
views/register.ejs
<h2>Register</h2>
<form action="/register" method="POST">
<input type="text" name="username" placeholder="Username" required />
<input type="password" name="password" placeholder="Password" required />
<input type="password" name="password2" placeholder="Confirm Password" required />
<button type="submit">Register</button>
</form>
<% if (success_msg) { %><p><%= success_msg %></p><% } %>
<% if (error_msg) { %><p><%= error_msg %></p><% } %>
views/login.ejs
<h2>Login</h2>
<form action="/login" method="POST">
<input type="text" name="username" placeholder="Username" required />
<input type="password" name="password" placeholder="Password" required />
<button type="submit">Login</button>
</form>
<% if (success_msg) { %><p><%= success_msg %></p><% } %>
<% if (error_msg) { %><p><%= error_msg %></p><% } %>
views/dashboard.ejs
<h2>Welcome, <%= user.username %>!</h2>
<a href="/logout">Logout</a>
dotenv
for sensitive configs like secret keys.node app.js
Visit:
http://localhost:5000/register
to registerhttp://localhost:5000/login
to log inhttp://localhost:5000/dashboard
after logging in✔ How to build an authentication system using Node.js & Express
✔ Storing and hashing passwords securely with bcrypt
✔ Managing sessions and access control
✔ Flash messaging for better UX
✔ Using EJS for simple UI
Q1: Why use bcrypt instead of plain-text passwords?
👉 Because plain-text passwords are dangerous! bcrypt hashes them, so even if someone hacks the DB, they can't read them easily.
Q2: What happens when a user logs out?
👉 We destroy the session, removing all their data from the server memory.
Q3: Can I use JWT instead of sessions?
👉 Absolutely. JWT is great for APIs. Sessions work well for traditional web apps.
What feature would you like to add to this authentication system next — email verification, forgot password, or social login?
Drop your vote in the comments below! 👇
Happy coding, and may your auth systems be secure! 🔐🚀
No comments yet. Be the first to comment!
Please log in to post a comment:
Sign in with Google