0

I have a project with the below Model, Controller, and Route File for user. I am wanting to implement sequelize, which I have managed to partially achieve using the account files below, however, I am struggling to work out how to implement logging in and ensuring a request has a valid token usijng user.ensureToken which would become account.ensureToken.

I'm fairly new to Node.Js so I'm not even sure where to start

user.model.js

const bcrypt = require('bcrypt');

const sql = require("./db.js");
const HashBits = require("../config/auth.config.js");
const faker = require('faker');

// constructor
const User = function(user) {
    this.first_name = user.first_name;
    this.last_name = user.last_name;
    this.mob_no = user.mob_no;
    this.user_name = user.user_name;
    this.password = user.password;
};

User.create = (newUser, result) => {
    bcrypt.hash(newUser.password, HashBits.saltRounds, (err, hash) => {
        newUser.password = hash;
        sql.query("INSERT INTO users SET ?", newUser, (err, res) => {
            if (err) {
                // console.log("error: ", err);
                result(err, null);
                return;
            }
            newID = res.insertId;
            // console.log("created user: ", { id: res.insertId, ...newUser });
            result(null, { id: res.insertId, ...newUser });
        });
        
    });
};

User.authenticate = (user,result) => {
    // sql.query(`SELECT * FROM customers WHERE id = ${customerId}`, (err, res) => {
    sql.query(`SELECT * FROM users WHERE user_name = '${user.user_name}'`, (err, res) => {
        // sql.query("SELECT * FROM users ", (err, res) => {
        if (err) {
            // console.log("error: ", err);
            result(err, null);
            return;
        }
        if(res.length !== 1){
            // console.log("error: found multiple users");
            result("error: found multiple users", null);
            return;
        }
        
        // console.log("Found user: ",res[0]);
        bcrypt.compare(user.password, res[0].password, function(err, res2) {
            if(res2){
                // console.log("Yes");
                result(null,res[0]);
            }else{
                // console.log("On ya bike");
                result("ERROR",null);
                // return;
            }
        });
    });
};
module.exports = User;

user.controller.js

const User = require("../models/user.model.js");

var jwt = require("jsonwebtoken");

const config = require("../config/auth.config.js");

// Create and Save a new User
exports.create = (req, res) => {
  // Validate request
  if (!req.body) {
    res.status(400).send({
      message: "Content can not be empty!"
    });
  }
  
  // Create a User
  const user = new User({
    first_name: req.body.first_name,
    last_name: req.body.last_name,
    mob_no: req.body.mob_no,
    user_name: req.body.user_name,
    password: req.body.password
  });
  
  // Save User in the database
  User.create(user, (err, data) => {
    if (err)
    res.status(500).send({
      message:
      err.message || "Some error occurred while creating the User."
    });
    else res.send(data);
  });
};

exports.authenticate = (req,res) => {
  
  if (!req.body) {
    res.status(400).send({
      message: "Content can not be empty!"
    });
  }
  
  const user = new User({
    user_name: req.body.user_name,
    password: req.body.password
  });
  
  User.authenticate(user, (err,data) => {
    if(err)
    res.status(500).send({
      message:
      err.message || "Some error occurred while authenticating the User."
    });
    else {
      var token = jwt.sign({ id: user.id }, config.secret, {
        expiresIn: 86400 // 24 hours
      });
      // res.send(data);
      
      res.status(200).send({
        id: data.id,
        username: data.user_name,
        accessToken: token
      });
    }
  });
};

exports.ensureToken = (req, res, next) => {
  let token = req.headers["x-access-token"];
  
  if (!token) {
    return res.status(403).send({
      message: "No token provided!"
    });
  }
  
  jwt.verify(token, config.secret, (err, decoded) => {
    if (err) {
      return res.status(401).send({
        message: "Unauthorized!"
      });
    }
    req.userId = decoded.id;
    next();
  });
}

user.routes.js

module.exports = app => {
    const users = require("../controllers/user.controller.js");
    // Create a new User
    app.post("/User", users.create);
    // Login
    app.post("/User/Login", users.authenticate);

  };

account.model.js

const bcrypt = require("bcrypt");


module.exports = (sequelize, Sequelize) => {
    const Account = sequelize.define("account", {
        firstName: {
            type: Sequelize.STRING
        },
        username: { 
            type: Sequelize.STRING
        },
        password: {
            type: Sequelize.STRING,
            set(value){
                const hash = bcrypt.hashSync(value, 10);
                this.setDataValue('password', hash);
            }
        }
    });

    return Account;
};

account.controller.js

const db = require("../models");
const Account = db.accounts;
const Op = db.Sequelize.Op;

var jwt = require("jsonwebtoken");

const config = require("../config/auth.config.js");

// Create and Save a new New
exports.create = (req, res) => {

    // Validate request
if (!req.body.username) {
    res.status(400).send({
    message: "Content can not be empty!"
    });
    return;
}

// Create a Site
const account = {
    firstName: req.body.firstName,
    username: req.body.username,
    password: req.body.password
};

Account.create(account)
.then(data => {
    res.send(data);
})
.catch(err => {
    res.status(500).send({
    message:
    err.message || "Some error occurred while creating the Account."
    });
});
};

exports.authenticate = (req,res) => {

    if (!req.body) {
        res.status(400).send({
        message: "Content can not be empty!"
        });
    }
    
    const account = new Account({
        username: req.body.username,
        password: req.body.password
    });

};

account.routes.js

module.exports = app => {
    const accounts = require("../controllers/account.controller.js");
    
    var router = require("express").Router();

    app.post("/account", accounts.create);

    app.post("/account/Login", accounts.authenticate);

};

1 Answer 1

1

you need to use jwt token for access token as you said and you are bcrypt password in model file which will be security issue you have to bcrypt password as soon as it comes in request I have implemented it in my answer remove code of password bcrypt from your model file

you have to import in your account.controller.js

  const db = require("../models");
  const User = db.user;
  require('dotenv').config();
  const Op = db.Sequelize.Op;
  const errors = require('../config/errors');
  const error = errors.errors;

  var jwt = require("jsonwebtoken");
  var bcrypt = require("bcryptjs");

 module.exports = {
 signup: async (req, res) => {
 if (!req.body.first_name|| !req.body.lastt_name || !req.body.password) {

  return res.status(200).send(error.MANDATORY_FIELDS);
}
try {
  // Save User to Database
  User.create({
    name: req.body.name,
    email: req.body.email,
    mo_no: req.body.mo_no,
    city: req.body.city,
    password: bcrypt.hashSync(req.body.password, 8),
    user_type: "admin"
  }).then(function (user) {
 
        return res.status(200).send(error.OK)
  })
    .catch(function (err) {
      console.log(err);
      return res.status(500).send(error.SERVER_ERROR)
    });
} catch (e) {
  console.log(e);
  return res.status(500).send(error.SERVER_ERROR)
}
},

signin: async (req, res) => {
if (!req.body.email || !req.body.password) {
  return res.status(200).send(error.MANDATORY_FIELDS);
}
User.findOne({
  where: {
    email: req.body.email
  }
}).then(function (user) {
  if (!user) {
    return res.status(404).send(error.USER_NOT_PRESENT);
  }

  const passwordIsValid = bcrypt.compareSync(
    req.body.password,
    user.password
  );

  if (!passwordIsValid) {
    return res.status(422).send(error.PASSWORD_MISSMATCH, {
      accessToken: null
    });
  }

  const token = jwt.sign({ id: user.id, first_name: user.first_name }, 
  process.env.secret, {
    expiresIn: 86400 // 24 hours
  });

  const authorities = [];
    return res.status(200).send({
      id: user.id,
      name: user.name,
      email: user.email,
      accessToken: token
    });
  });
})
  .catch(function (err) {
    console.log(err)
    return res.status(500).send(error.SERVER_ERROR);
  });
 }
}

than you have to create a separate folder for authorization like authorize.js or authJwt.js where you have to check is token is valid or not put this code in authorize.js

at decoding time secret token or password also needed which you have in .env file

const jwt = require("jsonwebtoken");

 verifyToken = (req, res, next) => {
 let token = req.headers["x-access-token"];

if (!token) {
  return res.status(403).send(error.TOKEN_NOT_PROVIDED);
}

jwt.verify(token, process.env.secret, (err, decoded) => {
 if (err) {
  return res.status(401).send(error.UNAUTHORIZED);
 }
 req.first_name= decoded.first_name;
 req.id = decoded.user_id
 next();
 });
};

const authJwt = {
  verifyToken: verifyToken
};
module.exports = authJwt;

than you have to import authorize.js file in your routes whenever you want like this

const authorize = require('../authorize.js');

module.exports = app => {
    const accounts = require("../controllers/account.controller.js");

     var router = require("express").Router();

     app.post("/account",  accounts.create);

     app.post("/account/Login", 
     authorize.verifyToken,accounts.authenticate);

};

it will be more effective if you genreate access token at signin time

Sign up to request clarification or add additional context in comments.

3 Comments

Hi @Arya, that makes sense how I would validate the jwt, I had that implemented in a similar fashion previously in the user controller with the function .ensureToken. The main issue I am facing is how to generate the jwt when a user signs in. Because I am using Sequelize to define the Account model, I'm not sure how to create a function to authenticate the account with username & password and return a jwt.
ok i am implementing my answer to generate jwt token at signin time
i have updated answer you can make changes according your app files and folders

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.