Tell us what’s happening:
Build JWT Protected Routes - Lesson 35, I have completed the assignment but I can’t get test 6 to pass when running the final set of tests.
Tests:
-
- ✓
POST /api/auth/registershould respond with status201and a token. -
- ✓
POST /api/auth/loginshould respond with status200and a token for valid credentials. -
- ✓
GET /api/auth/profilewithout a token should respond with status401. -
- ✓
GET /api/auth/profilewith a valid token should respond with status200and the user. -
- ✓
GET /api/admin/userswith a normal user’s token should respond with status403. -
- ✗
GET /api/admin/userswith an admin token should respond with200and users that omitpasswordHash. -
- ✓
POST /api/auth/logoutshould invalidate the token so reusing it responds with401.
Console:
{
"message": "An admin token should access /api/admin/users with status 200.: expected 401 to equal 200",
"showDiff": true,
"actual": 401,
"expected": 200,
"operator": "strictEqual",
"stack": "AssertionError: An admin token should access /api/admin/users with status 200.: expected 401 to equal 200\n at eval (eval at <anonymous> (file:///workspaces/back-end-development-and-apis/node_modules/@freecodecamp/freecodecamp-os/.freeCodeCamp/tooling/tests/test-worker.js:25:29), <anonymous>:26:8)\n at process.processTicksAndRejections (node:internal/process/task_queues:104:5)\n at async MessagePort.<anonymous> (file:///workspaces/back-end-development-and-apis/node_modules/@freecodecamp/freecodecamp-os/.freeCodeCamp/tooling/tests/test-worker.js:25:23)",
"type": "AssertionError"
}
Your code so far
-------------------index.js------------------
import express from "express";
import helmet from "helmet";
import authroutes from "./routes/auth.js";
import adminRoutes from "./routes/admin.js";
const PORT = process.env.PORT;
const app = express();
app.use(helmet());
app.use(express.json());
app.get("/", (req, res) => {
res.json({ message: "Auth API is running" });
});
app.use("/api/auth", authroutes);
app.use("/api/admin", adminRoutes);
app.use((err, req, res, next) => {
const statusCode = err.statusCode || 500;
res.status(statusCode).json({
"error": err.message
});
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}...`);
});
/Routes
-------------------- admin.js. ------------------
import express from "express";
import authenticate from "../middleware/authenticate.js";
import authorizeRole from "../middleware/authorize.js";
import { readUsers } from "../utils/db.js";
const router = express.Router();
router.get("/users", authenticate, authorizeRole("admin"), (req, res) => {
const users = readUsers().map(({ passwordHash, ...rest }) => rest);
return res.status(200).json(users);
});
export default router;
--------------------auth.js---------------
import express from "express";
import bcrypt from "bcryptjs";
import { randomUUID } from "crypto";
import { findByEmail, readUsers, writeUsers } from "../utils/db.js";
import { signToken } from "../utils/jwt.js";
import authenticate from "../middleware/authenticate.js";
import { blacklistToken } from "../utils/token-blacklist.js";
const router = express.Router();
router.post("/register", async (req, res) => {
const { email, password } = req.body;
if (!email || !password) {
return res.status(400).json({ message: "Email and password are required" });
}
if (findByEmail(email) != null) {
return res.status(409).json({ message: "Email already in use" });
}
const passwordHash = await bcrypt.hash(password, 10);
const newUser = {
id: randomUUID(),
email,
passwordHash,
role: "user"
};
const users = readUsers();
users.push(newUser);
writeUsers(users);
const token = signToken({ id: newUser.id, email: newUser.email, role: newUser.role });
res.status(201).json({ message: "User registered successfully.", token });
});
router.post("/login", async (req, res) => {
const { email, password } = req.body;
if (!email || !password) {
return res.status(400).json({ message: "Email and password required." });
}
const user = findByEmail(email);
if (user === null) {
return res.status(401).json({ message: "Invalid credentials" });
}
const match = await bcrypt.compare(password, user.passwordHash);
if (!match) return res.status(401).json({ message: "Invalid credentials" });
const token = signToken({ id: user.id, email: user.email, role: user.role });
res.status(200).json({ message: "login sucessful", token });
});
router.get("/profile", authenticate, (req, res) => {
res.status(200).json({ user: req.user });
});
router.post("/logout", authenticate, (req, res) => {
const token = req.headers.authorization.split(" ")[1];
blacklistToken(token);
res.status(200).json({ message: "Logged out successfully" });
});
export default router;
/Middleware
-----------------authenticate.js --------------
import { verifyToken } from "../utils/jwt.js";
import { isBlacklisted } from "../utils/token-blacklist.js";
export default function authenticate(req, res, next) {
const authentication = req.headers.authorization || req.headers.Authorization;
if (!authentication || !authentication.startsWith("Bearer ")) {
return res.status(401).json({ message: "No token provided" });
}
const token = authentication.split(" ")[1];
if (isBlacklisted(token)) {
return res.status(401).json({ message: "Token has been invalidated. Log in again." });
}
const payload = verifyToken(token);
if (!payload) {
return res.status(401).json({ message: "Invalid or expired token" });
}
req.user = payload;
next();
};
------------authorize.js---------------
export default function authorizeRole(role) {
return (req, res, next) => {
if (!req.user || req.user.role !== role) {
return res.status(403).json({ message: "Access denied" });
}
next();
};
};
/Utils
------------------db.js------------------
import path from "path";
import fs from "fs";
const DB_PATH = path.join(import.meta.dirname, "../data/users.json");
export function readUsers() {
const users = fs.readFileSync(DB_PATH, "utf-8").trim();
if (users) return JSON.parse(users);
else return [];
}
export function writeUsers(users) {
fs.writeFileSync(DB_PATH, JSON.stringify(users, null, 2));
}
export function findByEmail(email) {
return readUsers().find((u) => u.email === email) || null;
}
export function findById(id) {
return readUsers().find(u => u.id === id) || null;
}
------------------jwt.js-----------------
import jwt from "jsonwebtoken";
export function signToken(payload) {
return jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: "1d" });
}
export function verifyToken(token) {
try {
const payload = jwt.verify(token, process.env.JWT_SECRET);
return payload;
} catch (err) {
return null;
}
}
--------------token-blacklist.js-------------
const blacklist = new Set();
export function blacklistToken(token) {
blacklist.add(token);
}
export function isBlacklisted(token) {
return blacklist.has(token);
}
Your browser information:
User Agent is: Mozilla/5.0 (Macintosh; Intel Mac OS X __) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/...* Safari/***
Challenge Information:
Build JWT Protected Routes - Build JWT Protected Routes