DEV Community

kathir b
kathir b

Posted on

How to Build a Secure User Authentication System in Node.js

Introduction

User authentication is a critical part of any web application. In this tutorial, we'll build a secure authentication system in Node.js using JWT (JSON Web Token), bcrypt for password hashing, and Express.js for handling routes.

By the end of this guide, you'll be able to:

  • Register users securely
  • Hash passwords using bcrypt
  • Authenticate users using JWT
  • Protect API routes with middleware

Step 1: Set Up Your Node.js Project

First, create a new project and install dependencies:

mkdir auth-system && cd auth-system
npm init -y
npm install express bcryptjs jsonwebtoken dotenv cors mongoose
Enter fullscreen mode Exit fullscreen mode

Create a .env File

Create a .env file for environment variables:

PORT=5000
MONGO_URI=mongodb://localhost:27017/auth_db
JWT_SECRET=your_jwt_secret_key
Enter fullscreen mode Exit fullscreen mode

Step 2: Set Up Express Server

Create server.js:

require('dotenv').config();
const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
const userRoutes = require('./routes/userRoutes');

const app = express();
app.use(express.json());
app.use(cors());
app.use('/api/users', userRoutes);

mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true })
  .then(() => console.log('MongoDB Connected'))
  .catch(err => console.log(err));

const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
Enter fullscreen mode Exit fullscreen mode

Step 3: Create User Model

Create models/User.js:

const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
  name: { type: String, required: true },
  email: { type: String, required: true, unique: true },
  password: { type: String, required: true }
});
module.exports = mongoose.model('User', userSchema);
Enter fullscreen mode Exit fullscreen mode

Step 4: Implement User Registration

Create routes/userRoutes.js:

const express = require('express');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const User = require('../models/User');
const router = express.Router();

// Register user
router.post('/register', async (req, res) => {
  try {
    const { name, email, password } = req.body;
    const existingUser = await User.findOne({ email });
    if (existingUser) return res.status(400).json({ message: 'User already exists' });

    const hashedPassword = await bcrypt.hash(password, 10);
    const user = new User({ name, email, password: hashedPassword });
    await user.save();

    res.status(201).json({ message: 'User registered successfully' });
  } catch (error) {
    res.status(500).json({ message: 'Server error' });
  }
});

module.exports = router;
Enter fullscreen mode Exit fullscreen mode

Step 5: Implement User Login & JWT Authentication

Add login logic in userRoutes.js:

router.post('/login', async (req, res) => {
  try {
    const { email, password } = req.body;
    const user = await User.findOne({ email });
    if (!user) return res.status(400).json({ message: 'Invalid credentials' });

    const isMatch = await bcrypt.compare(password, user.password);
    if (!isMatch) return res.status(400).json({ message: 'Invalid credentials' });

    const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: '1h' });
    res.json({ token });
  } catch (error) {
    res.status(500).json({ message: 'Server error' });
  }
});
Enter fullscreen mode Exit fullscreen mode

Step 6: Protect API Routes with Middleware

Create middleware/auth.js:

const jwt = require('jsonwebtoken');
module.exports = (req, res, next) => {
  const token = req.header('Authorization');
  if (!token) return res.status(401).json({ message: 'Access Denied' });

  try {
    const verified = jwt.verify(token, process.env.JWT_SECRET);
    req.user = verified;
    next();
  } catch (error) {
    res.status(400).json({ message: 'Invalid Token' });
  }
};
Enter fullscreen mode Exit fullscreen mode

Apply middleware to protect routes:

const auth = require('../middleware/auth');
router.get('/profile', auth, (req, res) => {
  res.json({ message: 'Welcome to your profile' });
});
Enter fullscreen mode Exit fullscreen mode

Step 7: Test Your API with cURL or Postman

  • Register User:
  curl -X POST -H "Content-Type: application/json" -d '{"name": "John Doe", "email": "john@example.com", "password": "password123"}' http://localhost:5000/api/users/register
Enter fullscreen mode Exit fullscreen mode
  • Login User:
  curl -X POST -H "Content-Type: application/json" -d '{"email": "john@example.com", "password": "password123"}' http://localhost:5000/api/users/login
Enter fullscreen mode Exit fullscreen mode
  • Access Protected Route:
  curl -X GET -H "Authorization: Bearer YOUR_JWT_TOKEN" http://localhost:5000/api/users/profile
Enter fullscreen mode Exit fullscreen mode

Conclusion

You have successfully built a secure user authentication system in Node.js with JWT authentication! ๐ŸŽ‰

Next Steps:
โœ… Connect to a frontend (React/Angular/Vue)
โœ… Implement password reset functionality
โœ… Add role-based access control (RBAC)

Happy Coding! ๐Ÿš€

Top comments (0)