Search code examples
node.jsexpressjwtexpress-jwt

Can't set headers after they are sent. using JWT


I'm trying to create an authentication with JWT, when I created my method it's a function called verifyJWT () it starts firing this error ...

NOTE: Before constructing this function and using it in the route, I can send it calmly, the problem is when I do res.status (200) .send ({auth: true, token: jwtToken}); and then res.redirect ('/ home/ v1'); But really I do not know why this problem ..

What is the correct mode of user authentication and on subsequent routes?

LOGIN ROUTER:

const { body } = require('express-validator/check');

module.exports = (app) => {
    app.route('/')
    .get((req, res) => { app.controllers.login.controller.redirectRouter(app, req, res) });

    app.route('/login')
    .get((req, res)  => { app.controllers.login.controller.login(app, req, res); })
    .post([
        body('username').isString().isLength({ min: 1 }).not().isEmpty(),
        body('password').isString().isLength({ min: 1 }).not().isEmpty()
    ], (req, res) => { app.controllers.login.controller.checkLoginForm(app, req, res); });

}

LOGIN CONTROLLER ROUTER

const { validationResult } = require('express-validator/check');
const jwt = require('jsonwebtoken');

module.exports.redirectRouter = (app, req, res) => res.redirect('/login');

module.exports.login = (app, req, res) => { 
    const renderConfig = new app.models.services.utilities.Render("LOGIN", true);
    renderConfig.httpJSPResponseStatusCode = 200;

    res.render('login/view', renderConfig.config);
}

module.exports.checkLoginForm = (app, req, res) => {
    /** @description: RECEBE O RESULTADO DA VALIÇÃO DO FORMULÁRIO PELO {EXPRESS-VALIDATOR} */
    const errors = validationResult(req);

    /** @description: VERIFICA SE HOUVE ERRO NA VALIDAÇÃO DO FORMULÁRIO COM O {EXPRESS-VALIDATOR} */
    if (!errors.isEmpty()) {
        /** @description: CASO ALGUM DADO ESTEJA INCONSISTENTE RETORNA {ERROR: 401} DE {NÃO AUTORIZADO} */
        res.status(401).send("401 Não autorizado");
    } else {
        /** @description: CASO OS DADOS FOREM VÁLIDOS, ADICIONA OS VALORES DO BODY NAS VARIÁVEIS */
        const username = req.body.username,
              password = req.body.password;

        /** FUNÇÕES TEMPORÁRIAS */
        if(username === "1" && password === "1"){
            const userId = 10;
            const jwtToken = jwt.sign({ userId }, process.env.SECRET, {
                expiresIn: 300 // EXPIRA EM 5MIN
            });

            //res.status(200).send({ auth: true, token: jwtToken });
            res.redirect('/home/v1');
        } else {
            res.status(401).send("401 Não autorizado");
        }
    }


}

HOME ROUTER

    const jwtClass = require('../../models/services/JWT/controller.js');

    module.exports = (app) => {
        app.route('/home/v1/')
        .get(jwtClass.verifyJWT, (req, res) => {
            console.log("é get")
            //app.controllers.home.controller.home(app, req, res);
        }).post(jwtClass.verifyJWT, (req, res) => {
            console.log("é post")
            //app.controllers.home.controller.home(app, req, res);
        });
    }

** HOME CONTROLLER ROUTER **
module.exports.home = (app, req, res) => {
    res.render('home/view');
}

JWT FUNCTION METHOD

const jwt = require('jsonwebtoken');

module.exports.verifyJWT = (req, res, next) => {
    const jwtToken = req.headers['x-access-token'];

    if (!jwtToken) {
        return res.status(401).send({ auth: false, message: 'No token provided.' });
    } else {
        jwt.verify(jwtToken, process.env.SECRET, (error, decoded) => {
            if (error) {
                return res.status(500).send({ auth: false, message: 'Failed to authenticate token.' });
            } else {
                    console.log("ae")
                req.userId = decoded.id;
                next();
            }
        });
    }
}

Solution

  •  //res.status(200).send({ auth: true, token: jwtToken });
            res.redirect('/home/v1');
    

    You can't redirect after sending Response. Refer the way Request and Response work in REST api. What you can do here is Redirect first and Have the Auth Token sent after Redirection (in the Redirection Route). You need to Write login after Redirection.

    Update :

    Try adding the line res.status(200).send({ auth: true, token: jwtToken }); inside HOME ROUTER

    Also please import Proper Modules to HOME ROUTER.

        const jwtClass = require('../../models/services/JWT/controller.js');
    
        module.exports = (app) => {
            app.route('/home/v1/')
            .get(jwtClass.verifyJWT, (req, res) => {
                console.log("é get")
                //ADD HERE
              res.status(200).send({ auth: true, token: jwtToken });
                //app.controllers.home.controller.home(app, req, res);
            }).post(jwtClass.verifyJWT, (req, res) => {
                console.log("é post")
               //ADD HERE
                res.status(200).send({ auth: true, token: jwtToken });
                //app.controllers.home.controller.home(app, req, res);
            });
        }
    
    ** HOME CONTROLLER ROUTER **
    module.exports.home = (app, req, res) => {
        res.render('home/view');
    }