Why is req.body undefined when im using a body parser?

Issue

My req.body object keeps being undefined even though I’ve used app.use(express.urlencoded({ extended: false}));. At my html all my inputs have "name" attribute given and they match what I’ve written in this code. Can you help me solve this? Thank you.

JavaScript Code:

//Constantes
const express = require('express');
const port = process.env.PORT || 3000;
const exphbs = require("express-handlebars");
const passport = require("passport");               
const session = require("express-session"); 

//---------------
const bcrypt = require("bcrypt");   
//const passport = require("passport");           
const passport_local = require("passport-local");
const LocalStrategy = passport_local.Strategy;
const connection = require("./database");  
//-----------------


//Config
const app = express();
app.use(express.urlencoded({ extended: false}));
app.engine(".hbs", exphbs.engine());
app.set('view engine', ".hbs");

//--------------------

passport.use("local.signup", new LocalStrategy({
    usernameField: "email",
    passwordField: "password",
    passReqToCallback: true
}, async (username, password, req, done) => {
    console.log(req.body);
    const salt = await bcrypt.genSalt(10);
    const hash = await bcrypt.hash(password, salt);
    const user = { email: username, password: hash, nombre: req.body.nombre, apellido: req.body.apellido};
    const result = await connection.query("INSERT INTO usuarios SET ?", user);

    user.id = result.insertId;
    return done(null, user.id);
}));

passport.serializeUser((user, done) => {  
    return done(null, user.id);
 });
 passport.deserializeUser( async (id, done) => {    
     const rows = await connection.query(`SELECT id, email FROM usuarios WHERE id = ${id}`)
     return done(null, rows[0]);
 });

//-----------------------------------
//require("./passport");
app.use(passport.initialize());
app.use(session({
    secret: "secreto",  
    resave: false,
    saveUninitialized: true,
}));
app.use(passport.session());
app.listen(port, () => {
    console.log("listening on port " + port);
});

app.use(require("./routes/index.js"));
app.use(require("./routes/register.js"));

Html form that the users sees (all the "name" attributes match as they should):

<!-- Formulario de registro -->
<section class="container-fluid">
    <div class="row justify-content-center align-content-center m-5">
        <h1 class="text-center mt-5">Registro Administrador</h1>
        <div class="col-xl-4 col-lg-8 col-md-8 col-xs-12">
            <form action="/register" method="post" class=" border border-2 border-dark p-4 rounded">
                <div class="form-group p-2">
                    <label for="email">E-Mail <span class="text-danger">*</span></label>
                     <input id="email" class="form-control" type="email" placeholder="[email protected]" required name="email"  value="{{ email }}">
                </div>
                <div class="form-group p-2">
                    <label for="password">ContraseƱa <span class="text-danger">*</span></label>
                     <input id="password" class="form-control" type="password" placeholder="*********" required name="password">
                </div>
                <div class="form-group p-2">
                    <label for="nombre">nombre <span class="text-danger">*</span></label>
                     <input id="nombre" class="form-control" type="text" placeholder="nombre" required name="nombre">
                </div>
                <div class="form-group p-2">
                    <label for="apellido">apellido <span class="text-danger">*</span></label>
                     <input id="apellido" class="form-control" type="text" placeholder="apellido" required name="apellido">
                </div>
                <div class="d-grid p-2">
                    <button type="submit" class="btn btn-light btn-outline-dark outline">Registrarse</button>
                </div>
                <div class="d-grid p-2 ">
                    <a href="/login" class="btn btn-light btn-outline-dark outline">Ya tenes cuenta? Logeate!</a>
                </div>
            </form>
        </div>
    </div>
</section>

Solution

According to the documentation, the order of parameters passed to the LocalStrategy callback are…

req, username, password, done

With that in mind, your code should look like this

passport.use(
  "local.signup",
  new LocalStrategy(
    {
      usernameField: "email",
      passwordField: "password",
      passReqToCallback: true,
    },
    async (req, username, password, done) => { // req is the first parameter
      console.log(req.body);
      const salt = await bcrypt.genSalt(10);
      const hash = await bcrypt.hash(password, salt);
      const user = {
        email: username,
        password: hash,
        nombre: req.body.nombre,
        apellido: req.body.apellido,
      };
      const result = await connection.query("INSERT INTO usuarios SET ?", user);

      return done(null, result.insertId);
    }
  )
);

Answered By – Phil

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published