Overview

Secure auth flow with password verification via bcrypt.compare, JWT issuance for sessions, cookie-based storage, and logout that clears the token. Routes are protected with middleware that validates JWTs.

Stack

Endpoints

Auth Flow

app.post("/login", async (req, res) => {
  const { email, password } = req.body;
  const user = await User.findOne({ email });
  if (!user || !(await bcrypt.compare(password, user.password))) {
    return res.status(401).send("Invalid credentials");
  }

  const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET, {
    expiresIn: "1h",
  });
  res.cookie("token", token, { httpOnly: true, sameSite: "lax" });
  res.redirect("/dashboard");
});

app.get("/logout", (req, res) => {
  res.clearCookie("token");
  res.redirect("/login");
});

const authenticate = (req, res, next) => {
  const token = req.cookies.token;
  if (!token) return res.status(401).send("Access denied");

  jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => {
    if (err) return res.status(401).send("Invalid token");
    req.user = decoded;
    next();
  });
};

app.get("/dashboard", authenticate, (req, res) => {
  res.render("dashboard", { user: req.user });
});

Highlights