Lesson 15 +10 XP

Project 2: User Authentication & JWT Auth Service

Build a Production Authentication Service

In this project, you will build user registration, login with bcrypt hashing, and JWT token protection.

Complete Auth Pipeline Code

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

const app = express();
app.use(express.json());

const JWT_SECRET = "jwt_super_secret_project_key";
const usersDB = []; // In-memory database array

// REGISTER ENDPOINT: POST /api/auth/register
app.post("/api/auth/register", async (req, res) => {
  const { email, password } = req.body;

  if (!email || !password) {
    return res.status(400).json({ error: "Email and password are required" });
  }

  const existingUser = usersDB.find(u => u.email === email);
  if (existingUser) {
    return res.status(409).json({ error: "User already exists" });
  }

  // Hash password with bcrypt
  const hashedPassword = await bcrypt.hash(password, 10);
  const newUser = { id: usersDB.length + 1, email, password: hashedPassword };
  usersDB.push(newUser);

  res.status(201).json({ status: "success", message: "User registered successfully" });
});

// LOGIN ENDPOINT: POST /api/auth/login
app.post("/api/auth/login", async (req, res) => {
  const { email, password } = req.body;

  const user = usersDB.find(u => u.email === email);
  if (!user) {
    return res.status(401).json({ error: "Invalid credentials" });
  }

  // Compare entered password with stored bcrypt hash
  const isValid = await bcrypt.compare(password, user.password);
  if (!isValid) {
    return res.status(401).json({ error: "Invalid credentials" });
  }

  // Sign JWT token
  const token = jwt.sign({ userId: user.id, email: user.email }, JWT_SECRET, { expiresIn: "2h" });

  res.status(200).json({ status: "success", token });
});

// PROTECTED DASHBOARD: GET /api/auth/profile
app.get("/api/auth/profile", (req, res) => {
  const authHeader = req.headers.authorization;
  if (!authHeader || !authHeader.startsWith("Bearer ")) {
    return res.status(401).json({ error: "Access denied" });
  }

  const token = authHeader.split(" ")[1];
  try {
    const decoded = jwt.verify(token, JWT_SECRET);
    res.status(200).json({ status: "success", user: decoded });
  } catch (err) {
    res.status(403).json({ error: "Invalid or expired token" });
  }
});

TL;DR

  • Hash passwords during registration using bcrypt.hash.
  • Compare hashes during login using bcrypt.compare.
  • Issue JWT tokens and protect secure routes via Authorization Bearer headers.