Authentication & Security: Protecting Your Application

Authentication & Security: Protecting Your Application

Security is not a feature; it's a foundation. In a world of data breaches and cyber-attacks, protecting your users' identities and information is the most critical responsibility of a web developer. Authentication confirms who a user is, while Authorization determines what they are allowed to do.

This chapter covers the essentials of modern web security, from password hashing and JSON Web Tokens (JWT) to preventing common vulnerabilities like XSS and SQL Injection.


Why This Topic Matters

A single security flaw can ruin user trust and lead to legal or financial disaster. Mastering security allows you to:

  • Protect Sensitive Data: Ensure that personal information remains private and secure.
  • Manage User Identity: Build robust login systems using industry-standard tokens.
  • Defend Against Attacks: Identify and mitigate risks like Cross-Site Scripting (XSS) and Cross-Site Request Forgery (CSRF).
  • Implement Fine-Grained Control: Control exactly which users can access specific admin panels or API routes.

The Authentication Flow: JWT

Modern apps often use JSON Web Tokens (JWT) for stateless authentication. This means the server doesn't need to store a "session" in the database for every user.

Client1. Login (User/Pass)Server2. Sign & Return JWT3. Request + JWT Header


Password Security: Hashing with Bcrypt

Rule #1: Never store a password in plain text. If your database is compromised, every user's account is exposed.

Instead, use Hashing. A hash is a one-way mathematical function that turns a password into a unique string of characters.

import bcrypt from "bcrypt";

const saltRounds = 10;
const plainPassword = "myPassword123";

// Hashing (During Registration)
const hash = await bcrypt.hash(plainPassword, saltRounds);

// Comparing (During Login)
const isMatch = await bcrypt.compare(plainPassword, hash); // true or false

Authorization Middleware

Once a user is authenticated, you need to protect your API routes.

import jwt from "jsonwebtoken";

const authenticateToken = (req, res, next) => {
  const authHeader = req.headers['authorization'];
  const token = authHeader && authHeader.split(' ')[1];

  if (!token) return res.sendStatus(401); // Unauthorized

  jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, user) => {
    if (err) return res.sendStatus(403); // Forbidden
    req.user = user;
    next();
  });
};

// Use it on a route
app.get('/admin', authenticateToken, (req, res) => {
  res.json({ data: "Welcome, Admin!" });
});

Common Security Threats

  1. SQL Injection: Attackers send malicious SQL commands in input fields. (Fixed by using ORMs like Prisma).
  2. XSS (Cross-Site Scripting): Injecting malicious scripts into web pages seen by other users. (Fixed by sanitizing input and using textContent).
  3. Broken Access Control: Forgetting to check if a user is an "Admin" before letting them delete a record.
  4. Sensitive Data Exposure: Sending too much info in an API response (e.g., sending the user's password hash back to the client).

Production Security Checklist

  • Use HTTPS everywhere (SSL/TLS).
  • Store secrets in .env files (never commit them to Git!).
  • Set secure headers using the helmet middleware.
  • Use rate limiting to prevent brute-force login attempts.
  • Regularly run npm audit to check for library vulnerabilities.

Mini Exercises

  1. The Hasher: Create a script that takes a string from the command line and logs its Bcrypt hash.
  2. Token Generator: Write a function that creates a JWT containing a userId and an isAdmin flag. Set it to expire in 30 minutes.
  3. Safe Route: Create a mock Express route /dashboard that returns a 401 error if no Authorization header is present.
  4. Data Sanitizer: Write a function that takes a string and replaces any <script> tags with [REMOVED] to prevent XSS.
  5. Environment Setup: Create a .env file with a JWT_SECRET. Write a script that reads this secret and logs its length.

Review Questions

  1. What is the difference between Authentication and Authorization?
  2. Why is "salting" important when hashing passwords?
  3. What are the three parts of a JWT? (Header, Payload, Signature).
  4. Why should you never commit your .env file to GitHub?
  5. How does an ORM like Prisma protect you from SQL Injection?

Reference Checklist

  • I understand why plain-text passwords are a security disaster.
  • I can use Bcrypt to hash and compare passwords.
  • I understand the JWT flow (Login -> Token -> Request).
  • I can write middleware to protect routes.
  • I know how to use environment variables for secrets.
  • I understand the risks of XSS and SQL Injection.