I'm trying to make a simple API with passport-jwt and passport-local-mongoose, I set all the JWT functions up and make some routes, like one to register and one to sign in! One ogf these routes receives a get request to list all documents that exists on the database, however, when I try to make this request the server gives me this error:
DError [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:533:11)
at ServerResponse.header (/home/mdsp/Documents/Challenges/passportJWTMongoose/node_modules/express/lib/response.js:771:10)
at ServerResponse.json (/home/mdsp/Documents/Challenges/passportJWTMongoose/node_modules/express/lib/response.js:264:10)
at /home/mdsp/Documents/Challenges/passportJWTMongoose/src/controllers/Document.ts:9:18
at step (/home/mdsp/Documents/Challenges/passportJWTMongoose/src/controllers/Document.ts:33:23)
at Object.next (/home/mdsp/Documents/Challenges/passportJWTMongoose/src/controllers/Document.ts:14:53)
at fulfilled (/home/mdsp/Documents/Challenges/passportJWTMongoose/src/controllers/Document.ts:5:58)
at processTicksAndRejections (internal/process/task_queues.js:97:5) {
code: 'ERR_HTTP_HEADERS_SENT'
}
I searched about it and found that this error usually is caused because a double callback or something like that, but I'm not able to specify where is the error and why it's happening this with my code. Here's the Document controller:
import { Request, Response } from "express";
import DocumentModel from "../database/models/Document";
class Document {
async index(req: Request, res: Response) {
try {
const documents = await DocumentModel.find();
return res.status(200).json(documents);
} catch (err) {
console.log(err);
return res.status(400).json({ error: err.message });
}
}
}
export default new Document();
This is my routes file:
import { Router } from "express";
import auth from "./middleware/auth";
import documentController from "./controllers/Document";
const router = Router();
router.get("/", (req, res) => {
return res.json({ home: "My homepage" });
});
router.get("/documents", auth.requireJWT, documentController.index);
router.post("/auth/register", auth.register, auth.signJWTForUser);
router.post("/auth", auth.signIn, auth.signJWTForUser);
export default router;
And here's is the auth.ts, where I configured all the passport and JWT functions to refister, sign in and request a JWT token:
import { config } from "dotenv";
config();
import passport from "passport";
import JWT from "jsonwebtoken";
import { Strategy, ExtractJwt } from "passport-jwt";
import { Request, Response, NextFunction } from "express";
import UserModel from "../database/models/User";
interface IRequestUser extends Express.User {
_id?: string;
email?: string;
firstName?: string;
lastName?: string;
}
const jwtSecret = process.env.JWT_SECRET!;
const jwtAlgorithm = "HS256";
const jwtExpiresIn = "7 days";
passport.use(UserModel.createStrategy());
async function register(req: Request, res: Response, next: NextFunction) {
try {
const { email, firstName, lastName, password } = req.body;
const user = new UserModel({
email: email,
firstName: firstName,
lastName: lastName,
});
const registeredUser = await UserModel.register(user, password);
req.user = registeredUser;
return next();
} catch (err) {
console.log(err.message);
return next(err);
}
}
passport.use(
new Strategy(
{
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: jwtSecret,
algorithms: [jwtAlgorithm],
},
async (payload, done) => {
try {
const foundUser = await UserModel.findById(payload.sub);
foundUser && done(null, foundUser);
done(null, false);
} catch (err) {
console.log(err.message);
done(err, false);
}
}
)
);
function signJWTForUser(req: Request, res: Response) {
if (req.user) {
const user: IRequestUser = req.user;
const token = JWT.sign({ email: user.email }, jwtSecret, {
algorithm: jwtAlgorithm,
expiresIn: jwtExpiresIn,
subject: user._id!.toString(),
});
return res.json({ token });
}
}
export default {
initialize: passport.initialize(),
register,
signIn: passport.authenticate("local", { session: false }),
requireJWT: passport.authenticate("jwt", { session: false }),
signJWTForUser,
};
What should I improve on my controller and what is causing this error?