0

I'm currently in the process of writing a "modular" REST API that uses JWT for authentication. It's been a stressful process, but I've been encountering issues and fixing them one by one. Sadly I've stumbled upon an issue I'm not exactly sure how to fix.

Basically, I have an auth endpoint where I make a POST request with new user information, but for some reason, I keep getting the error "Unhandled rejection Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client"

The way this endpoint works is that it calls a controller function called createUser which can be seen below:

'use strict'

const UserService = require('../../services/users')
const User = require('../../domain/user')
const TokenService = require('../../services/tokens')

const config = require("../../config/auth.config"); //secret key

const tokenService = new TokenService()
const userService = new UserService()
const mailService = require('../../services/mail')

class UserController {
  createUser(req, res, next) {
    console.log("Create user!")
    console.log("User: " + JSON.stringify(req.body));
    const user = new User(req.body)

    userService.createNewUser(user).then(user => {
      return tokenService.createToken({
        firstName: user.firstName,
        lastName: user.lastName,
        email: user.email,
      }, config.secret)
    }).then(token => {
      // who cares if it fails, we have a resend option
      return mailService.sendActivationEmail(user.email, token)
    }).then(() => {
      res.status(201).send()
    }).catch(err => res.status(500).send(err.message))
    next();
  }

  activateUser(req, res, next) {
    const token = req.query.token
    tokenService.verifyToken(token, config.secret).then(user => {
      if (!user || !user.email) {
        throw new Error('Token not valid')
      }
      return userService.activateUser(user.email)
    }).then(() => {
      res.status(202).send({apiToken: token})
    }).catch(err => {
      res.status(500).send(err.message)
    })
  }
}

module.exports = UserController;

Then it calls a user service I made and then a token service which handles token creation, verification etc. With a bunch of logging statements, I've narrowed down the issue to the TokenService which contains a createToken function which is below:

'use strict'

const jwt = require('jsonwebtoken')

module.exports = (embeddedData, secretKey) => {
  console.log('Embedded Data:' + JSON.stringify(embeddedData))
  return Promise.resolve(jwt.sign(embeddedData, secretKey))
  console.log("Token created.");
}

After the Embedded Data output which outputs the JSON: {"firstName":"John","lastName":"Smith","email":"johnsmith123@gmail.com"}

The "Cannot set headers after they are sent to the client" happens there, therefore "Token created" is not outputting

I have searched over StackOverflow but from what I'm seeing, I think I am doing everything right. Incase it helps, I'm defining my route as:

  app.post("/api/auth/signup",
    controller.createUser
  );

I would appreciate any help, I've been scratching my head over this and am not sure what to do next.

Thanks!

sm0keman1
  • 168
  • 1
  • 4
  • 12
  • Does this help? https://stackoverflow.com/questions/7042340/error-cant-set-headers-after-they-are-sent-to-the-client – Christian Oct 15 '20 at 07:26
  • 1
    in general this exception happens when a piece of code already send a response and your programs run into another piece of code sending another response. As http only give the possibilty to send one, and only one response. – mJehanno Oct 15 '20 at 07:26
  • 1
    You are sending the response and again you are calling next middleware. next(). – Mohan Krishna Sai Oct 15 '20 at 07:30
  • @MohanKrishnaSai Wow, I forgot I put next() there, was testing something earlier and forgot to remove it to see how something works. That was the issue...woops – sm0keman1 Oct 15 '20 at 08:11

1 Answers1

1

You are sending the response and again you are calling next middleware. next().