CPCODELAB
Express

Authentication with JWT

13 min read

Authentication with JWT

JSON Web Tokens (JWT) are a compact, self-contained way to transmit claims between a client and server. The server signs the token with a secret; the client sends it in the Authorization header on every subsequent request. The server verifies the signature without needing to query a session store.

bash
npm install jsonwebtoken
npm install --save-dev @types/jsonwebtoken

Signing a Token on Login

js
import jwt from "jsonwebtoken";

const JWT_SECRET = process.env.JWT_SECRET as string;

app.post("/auth/login", async (req, res) => {
  const { email, password } = req.body;
  // Replace with real DB lookup and password hash check
  const user = { id: 1, email: "alice@example.com", role: "user" };
  const isValid = password === "correct-password";

  if (!isValid) {
    return res.status(401).json({ error: "Invalid credentials" });
  }

  const token = jwt.sign(
    { sub: user.id, email: user.email, role: user.role },
    JWT_SECRET,
    { expiresIn: "7d" }
  );

  res.json({ token });
});

Verifying the Token in Middleware

js
function authenticate(req, res, next) {
  const authHeader = req.headers["authorization"];
  const token = authHeader?.startsWith("Bearer ")
    ? authHeader.slice(7)
    : null;

  if (!token) {
    return res.status(401).json({ error: "No token provided" });
  }

  try {
    const payload = jwt.verify(token, JWT_SECRET);
    req.user = payload; // attach to request for downstream handlers
    next();
  } catch (err) {
    res.status(401).json({ error: "Invalid or expired token" });
  }
}

// Protect a route
app.get("/profile", authenticate, (req, res) => {
  res.json({ user: req.user });
});

Store JWT_SECRET in an environment variable — never in source code. Use at least 256 bits of entropy. Rotate the secret immediately if it is ever leaked.

Ready to test yourself?
Practice Express— quiz & coding exercises