07 - Authentication & Security in Node.js


Introduction

Security is a critical aspect of web development, especially when handling user authentication and sensitive data. In this chapter, we will cover authentication methods, password hashing, JWT-based authentication, and security best practices for Node.js applications.



1. Authentication Methods

There are multiple ways to authenticate users in a Node.js application:

  • Session-based authentication (using cookies and sessions)
  • Token-based authentication (using JSON Web Tokens - JWT)
  • OAuth authentication (e.g., Google, Facebook, GitHub login)

We will focus on JWT-based authentication, which is widely used for modern web applications and APIs.



2. Hashing Passwords with bcrypt

Storing passwords in plain text is a major security risk. Instead, passwords should be hashed before storage.


Install bcrypt

npm install bcrypt

Example: Hashing a Password

const bcrypt = require("bcrypt");
const saltRounds = 10;

const hashPassword = async (password) => {
    const hashedPassword = await bcrypt.hash(password, saltRounds);
    console.log("Hashed Password:", hashedPassword);
};

hashPassword("mySecurePassword");

Example: Verifying a Password

const verifyPassword = async (password, hash) => {
    const match = await bcrypt.compare(password, hash);
    console.log("Password Match:", match);
};


3. Implementing JWT Authentication

JWT (JSON Web Tokens) is a popular method for secure authentication in web applications.


Install jsonwebtoken

npm install jsonwebtoken

Example: Generating a JWT Token

const jwt = require("jsonwebtoken");
const secretKey = "supersecretkey";

const generateToken = (user) => {
    return jwt.sign({ id: user.id, username: user.username }, secretKey, { expiresIn: "1h" });
};

const token = generateToken({ id: 1, username: "Alice" });
console.log("JWT Token:", token);

Example: Verifying a JWT Token

const verifyToken = (token) => {
    try {
        const decoded = jwt.verify(token, secretKey);
        console.log("Token Decoded:", decoded);
    } catch (err) {
        console.log("Invalid Token");
    }
};


4. Implementing Authentication in Express.js


Install Required Packages

npm install express jsonwebtoken bcrypt

Example: Setting Up Authentication Routes

const express = require("express");
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");

const app = express();
app.use(express.json());
const users = [];
const secretKey = "supersecretkey";

// Register Route
app.post("/register", async (req, res) => {
    const hashedPassword = await bcrypt.hash(req.body.password, 10);
    users.push({ username: req.body.username, password: hashedPassword });
    res.status(201).send("User Registered");
});

// Login Route
app.post("/login", async (req, res) => {
    const user = users.find(u => u.username === req.body.username);
    if (!user || !(await bcrypt.compare(req.body.password, user.password))) {
        return res.status(403).send("Invalid credentials");
    }
    const token = jwt.sign({ username: user.username }, secretKey, { expiresIn: "1h" });
    res.json({ token });
});

// Protected Route
app.get("/protected", (req, res) => {
    const token = req.headers.authorization;
    if (!token) return res.status(401).send("Access Denied");
    try {
        const verified = jwt.verify(token, secretKey);
        res.send("Protected content for " + verified.username);
    } catch {
        res.status(403).send("Invalid token");
    }
});

app.listen(3000, () => console.log("Server running on port 3000"));


5. Security Best Practices in Node.js

To improve security, follow these best practices:

  • Use environment variables for secrets (dotenv package)
  • Limit API request rates to prevent abuse (use express-rate-limit)
  • Validate user input to prevent SQL Injection & XSS (use express-validator)
  • Use HTTPS for encrypted communication
  • Enable CORS properly when working with APIs

Example: Using dotenv for Environment Variables

npm install dotenv
require("dotenv").config();
const secretKey = process.env.SECRET_KEY;

Example: Rate Limiting API Requests

npm install express-rate-limit
const rateLimit = require("express-rate-limit");
const limiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 100 });
app.use(limiter);


šŸ† Exercises

  • 1. Create a registration and login system using bcrypt and JWT.
  • 2. Implement middleware to protect a route using JWT authentication.
  • 3. Store sensitive values using environment variables and dotenv.
  • 4. Implement rate-limiting to prevent brute-force attacks.
  • 5. Improve your authentication system by adding password reset functionality.


Conclusion

Authentication and security are essential in any web application. This chapter covered password hashing, JWT authentication, secure routes, and best practices to protect your Node.js applications.


NoFuture - A new way to learn it stuff

Sn0wAlice

NoFuture Menthor - Cybersec Analyst

I'm Alice Snow, a cybersecurity professional with a passion for Blue Team operations, defensive security, and compliance. I focus on creating practical solutions to help organizations strengthen their security posture. Iā€™m also involved in offensive CI/CD research and incident detection, always looking for ways to bridge the gap between security theory and real-world application.

Profile Profile