Build a Login, Logout, and Register System in Express.js (2025) – Step-by-Step Guide

Author

Kritim Yantra

Jul 31, 2025

Build a Login, Logout, and Register System in Express.js (2025) – Step-by-Step Guide

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.


🌟 What You’ll Build

✅ 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


🛠️ Tech Stack

  • Node.js & Express.js – Backend logic
  • MongoDB & Mongoose – Database
  • bcryptjs – For hashing passwords 🔐
  • express-session – To manage sessions
  • connect-flash – Flash message middleware
  • EJS – Templating engine for rendering pages

💡 Note: You can use any database or frontend, but this tutorial keeps things simple and clean.


🧱 1. Project Setup

🗂️ Step 1: Initialize Your Project

mkdir express-auth-app
cd express-auth-app
npm init -y

📦 Step 2: Install Dependencies

npm install express mongoose bcryptjs express-session connect-flash ejs body-parser

🧩 2. Folder Structure

express-auth-app/
│
├── models/
│   └── User.js
├── views/
│   ├── login.ejs
│   ├── register.ejs
│   └── dashboard.ejs
├── routes/
│   └── auth.js
├── app.js
└── .env

🛠️ 3. Creating User Model

models/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);

🧠 4. Setting Up Express Server

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}`));

🧭 5. Creating Auth Routes

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;

🖥️ 6. EJS Views

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>

🛡️ 7. Security Tips for Production

  • Always hash passwords before storing them.
  • Use dotenv for sensitive configs like secret keys.
  • Sanitize user input to prevent XSS/SQL Injection.
  • Use HTTPS in production.

🚀 Run Your App

node app.js

Visit:

  • http://localhost:5000/register to register
  • http://localhost:5000/login to log in
  • http://localhost:5000/dashboard after logging in

✅ Recap: What You Learned

✔ 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


💬 Bonus Q&A

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.


 Question for You:

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! 🔐🚀

Tags

Comments

No comments yet. Be the first to comment!

Please log in to post a comment:

Sign in with Google

Related Posts