bcrypt Error: Illegal arguments: string, undefined - node.js

I got these errores when I try to post the http://localhost:5000/user/login url with postman
Error: Illegal arguments: string, undefined
at _async (C:\Users\Raghava\Desktop\react_vite\server\node_modules\bcryptjs\dist\bcrypt.js:286:46)
at C:\Users\Raghava\Desktop\react_vite\server\node_modules\bcryptjs\dist\bcrypt.js:307:17
at new Promise ()
at Object.bcrypt.compare (C:\Users\Raghava\Desktop\react_vite\server\node_modules\bcryptjs\dist\bcrypt.js:306:20) at C:\Users\Raghava\Desktop\react_vite\server\router\UserRouter.js:106:34
at processTicksAndRejections (internal/process/task_queues.js:93:5)
server.js
const express = require("express");
const cors = require("cors");
const dotenv = require("dotenv");
const mongoose = require("mongoose");
const authroute = require("./router/UserRouter");
//config the express
const app = express();
//config the cors
app.use(cors());
//config the body-parser
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
//config the .env
dotenv.config({ path: "./config/config.env" });
//port
const port = 5000;
//connect to database
mongoose
.connect(process.env.MONGO_DB_URL, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() => console.log("connected to database successfully..."))
.catch((err) => console.log(err));
//config the routes
app.use("/user", authroute);
//starting the server
app.listen(port, () => {
console.log(`server is started at posrt ${port}`);
});
userRouter.js
const express = require("express");
const Router = express.Router();
const User = require("../models/User");
const bcrypt = require("bcryptjs");
const gravatar = require("gravatar");
const jwt = require("jsonwebtoken");
const { check, validationResult } = require("express-validator/check");
Router.post(
"/register",
[
check("name").notEmpty().withMessage("name is required"),
check("email").isEmail().withMessage("proper email is required"),
check("password")
.isLength({ min: 6 })
.withMessage("min 6 chars for password"),
],
async (req, res) => {
let errors = validationResult(req);
//if error containes
if (!errors.isEmpty()) {
return res.status(400).json({
errors: errors.array(),
});
}
try {
let { name, email, password } = req.body;
//user exist
let user = await User.findOne({ email });
if (user) {
return res.status(400).json({
errors: [{ msg: "user alredy exist" }],
});
}
//encrypt the password
let salt = await bcrypt.genSalt(10);
password = await bcrypt.hash(password, salt);
//get the avatar
let avatar = gravatar.url(email, {
s: "200",
r: "pg",
});
//store the user
user = new User({ name, email, password, avatar });
await user.save();
//json web token
let payload = {
user: {
id: user.id,
},
};
jwt.sign(payload, process.env.JWT_SECRET_KEY, (err, token) => {
if (err) {
throw err;
}
res.status(200).json({
result: "success",
token: token,
});
});
} catch (error) {
console.error(error);
res.status(500).json({
errors: [{ msg: error.message }],
});
}
}
);
Router.post(
"/login",
[
check("email").isEmail().withMessage("proper email is required"),
check("password").notEmpty().withMessage("password is required"),
],
async (req, res) => {
let errors = validationResult(req);
//if error containes
if (!errors.isEmpty()) {
return res.status(400).json({
errors: errors.array(),
});
}
try {
let { email, password } = req.body;
//check for email
let user = await User.findOne({ email });
if (!user) {
return res.status(400).json({ errors: [{ msg: "invalid credentials" }] });
}
//compare password
let isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res.status(400).json({ errors: [{ msg: "invalid credentials" }] });
}
//json web token
let payload = {
user: {
id: user.id,
},
};
jwt.sign(payload, process.env.JWT_SECRET_KEY, (err, token) => {
if (err) {
throw err;
}
res.status(200).json({
result: "success",
token: token,
});
});
} catch (error) {
console.error(error);
res.status(500).json({
errors: [{ msg: error.message }],
});
}
}
);
module.exports = Router;

It's most likely throwing and error because your code does not return after you check if the user exists:
let user = await User.findOne({ email });
if (!user) {
res.status(400).json({ errors: [{ msg: "invalid credentials" }] });
// most likely still runs code after this because it is not returning.
}
Please add the return keyword before res.status(400).json({ errors: [{ msg: "invalid credentials" }] }).
Final Code:
if (!user) {
return res.status(400).json({ errors: [{ msg: "invalid credentials" }] });
}
Additionally, I looked over your code before the error. You do await bcrypt.genSalt(10) and await bcrypt.hash(password, salt). If you take a look at the documentation, you need to passing in a callback for the async version. If you want to use the sync version and not use a callback, please do, bcrypt.genSaltSync() and bcrypt.hashSync().

Related

How to get all users from MongoDB?

I'm trying to get all my users from MongoDB, I've readed all documentations, but nothing helps.. What I'm trying to do is set my back-end mainController and create a get request which helps me get all users in front, so I can display them in my page. I'm still learning how to work with MongoDB, so sorry for my awful question.
mainController:
const uid = require('uid-safe')
const bcrypt = require('bcrypt')
const UserSchema = require('../schemas/UserSchema');
const { db } = require('../schemas/UserSchema');
const { default: mongoose } = require('mongoose');
module.exports = {
register: async (req, res) => {
const { username, email, password, image, city, country, firstName, lastName, phone, gender, birth } = req.body;
const userExists = await UserSchema.findOne({ username });
if (userExists) {
return res.send({ error: true, message: 'User with this username exists', data: null });
}
const emailExists = await UserSchema.findOne({ email });
if (emailExists) {
return res.send({ error: true, message: 'User with this email exists', data: null });
}
const id = await uid(7);
const hashedPass = await bcrypt.hash(password, 3);
const user = new UserSchema({
secret: id,
username,
email,
password: hashedPass,
image,
city,
country,
firstName,
lastName,
phone,
gender,
birth
});
await user.save();
return res.send({ error: false, message: 'User successfully registrated!', data: null });
},
login: async (req, res) => {
const { username, password } = req.body;
const loginUser = await UserSchema.findOne({ username });
if (loginUser) {
const passMatch = bcrypt.compare(password, loginUser.password)
if (passMatch) {
return res.send({ error: false, message: `Welcome back ${username}!`, data: loginUser })
}
return res.send({ error: true, message: 'Invalid password', data: null });
};
return res.send({ error: true, message: 'Invalid username', data: null });
},
getSingleUser: async (req, res) => {
const { secret } = req.params;
const findUser = await UserSchema.findOne({ secret });
if (findUser) {
return res.send({ error: false, message: 'User found', data: findUser });
}
return res.send({ error: true, message: 'User not found', data: null });
},
updateUser: async (req, res) => {
try {
const updateduser = await User.updateOne({ secret: req.params.secret }, { $set: req.body });
res.status(200).json(updateduser);
} catch (error) {
res.status(400).json({ message: error.message });
}
}
};
mainRouter:
const express = require('express')
const { login, register, getSingleUser, authSession, usersApi } = require("../controller/mainController")
const { loginValidate, registerValidate } = require("../middleware/authValidator")
const mainRouter = express.Router()
mainRouter.post('/register', registerValidate, register);
mainRouter.post('/login', loginValidate, login);
mainRouter.get('/user/:secret', getSingleUser)
module.exports = mainRouter;
Thank you!
I think you can use the find function.
const uid = require('uid-safe')
const bcrypt = require('bcrypt')
const UserSchema = require('../schemas/UserSchema');
const { db } = require('../schemas/UserSchema');
const { default: mongoose } = require('mongoose');
module.exports = {
register: async (req, res) => {
const { username, email, password, image, city, country, firstName, lastName, phone, gender, birth } = req.body;
const userExists = await UserSchema.findOne({ username });
if (userExists) {
return res.send({ error: true, message: 'User with this username exists', data: null });
}
const emailExists = await UserSchema.findOne({ email });
if (emailExists) {
return res.send({ error: true, message: 'User with this email exists', data: null });
}
const id = await uid(7);
const hashedPass = await bcrypt.hash(password, 3);
const user = new UserSchema({
secret: id,
username,
email,
password: hashedPass,
image,
city,
country,
firstName,
lastName,
phone,
gender,
birth
});
await user.save();
return res.send({ error: false, message: 'User successfully registrated!', data: null });
},
login: async (req, res) => {
const { username, password } = req.body;
const loginUser = await UserSchema.findOne({ username });
if (loginUser) {
const passMatch = bcrypt.compare(password, loginUser.password)
if (passMatch) {
return res.send({ error: false, message: `Welcome back ${username}!`, data: loginUser })
}
return res.send({ error: true, message: 'Invalid password', data: null });
};
return res.send({ error: true, message: 'Invalid username', data: null });
},
getSingleUser: async (req, res) => {
const { secret } = req.params;
const findUser = await UserSchema.findOne({ secret });
if (findUser) {
return res.send({ error: false, message: 'User found', data: findUser });
}
return res.send({ error: true, message: 'User not found', data: null });
},
updateUser: async (req, res) => {
try {
const updateduser = await User.updateOne({ secret: req.params.secret }, { $set: req.body });
res.status(200).json(updateduser);
} catch (error) {
res.status(400).json({ message: error.message });
}
},
getAllUsers: async(req, res) => {
try {
const allUser = await User.find({});
res.status(200).json(allUser);
} catch (error) {
res.status(400).json({ message: error.message });
}
}
};
const express = require('express')
const { login, register, getSingleUser, authSession, usersApi, getAllUsers } = require("../controller/mainController")
const { loginValidate, registerValidate } = require("../middleware/authValidator")
const mainRouter = express.Router()
mainRouter.post('/register', registerValidate, register);
mainRouter.post('/login', loginValidate, login);
mainRouter.get('/user/all', getAllUsers);
mainRouter.get('/user/:secret', getSingleUser);
module.exports = mainRouter;

While Verifying email and reseting password, only the first created/registered user is being valid

Scenario : When I create/register user1 ,the verification mail is sent to that email id and he(user1) is being verified successfully and I am able to change password for user1.
After creating user1 , I am creating/registering user2 ,where the verification email is sent to the account .After clicking the link , it's becomes INVALID
Overall , I am only able to create one user
Languages used : MERN stack
Backend => route.js :
const express = require("express");
const router = express.Router();
const User = require("../models/userModel");
const Doctor = require("../models/doctorModel");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const authMiddleware = require("../middlewares/authMiddleware");
const sendEmail = require("../utils/sendMail");
const Token = require("../models/tokenModel");
const Appointment = require("../models/appointmentModel");
const moment = require("moment");
router.post("/register", async (req, res) => {
try {
const userExists = await User.findOne({ email: req.body.email });
if (userExists) {
return res
.status(200)
.send({ message: "User already exists", success: false });
}
const password = req.body.password;
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(password, salt);
req.body.password = hashedPassword;
const newuser = new User(req.body);
const result = await newuser.save();
await sendEmail(result, "verifyemail");
res
.status(200)
.send({ message: "User created successfully", success: true });
} catch (error) {
console.log(error);
res
.status(500)
.send({ message: "Error creating user", success: false, error });
}
});
router.post("/login", async (req, res) => {
try {
const result = await User.findOne({ data: req.body.userId });
console.log(result);
const user = await User.findOne({ email: req.body.email });
if (!user) {
return res
.status(200)
.send({ message: "User does not exist", success: false });
}
if (user.isVerified === false) {
return res
.status(200)
.send({ message: "User not Verified", success: false });
}
const isMatch = await bcrypt.compare(req.body.password, user.password);
if (!isMatch) {
return res
.status(200)
.send({ message: "Password is incorrect", success: false });
} else {
const dataToBeSentToFrontend = {
id: user._id,
email: user.email,
name: user.name,
};
const token = jwt.sign(dataToBeSentToFrontend, process.env.JWT_SECRET, {
expiresIn: "1d",
});
res
.status(200)
.send({ message: "Login successful", success: true, data: token });
}
} catch (error) {
console.log(error);
res
.status(500)
.send({ message: "Error logging in", success: false, error });
}
});
router.post("/get-user-info-by-id", authMiddleware, async (req, res) => {
try {
const user = await User.findOne({ _id: req.body.userId });
user.password = undefined;
if (!user) {
return res
.status(200)
.send({ message: "User does not exist", success: false });
} else {
res.status(200).send({
success: true,
data: user,
});
}
} catch (error) {
res
.status(500)
.send({ message: "Error getting user info", success: false, error });
}
});
router.post("/send-password-reset-link", async (req, res) => {
try {
const result = await User.findOne({ email: req.body.email });
await sendEmail(result, "resetpassword");
res.send({
success: true,
message: "Password reset link sent to your email successfully",
});
} catch (error) {
res.status(500).send(error);
}
});
router.post("/resetpassword", async (req, res) => {
try {
const tokenData = await Token.findOne({ token: req.body.token });
if (tokenData) {
const password = req.body.password;
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(password, salt);
await User.findOneAndUpdate({
_id: tokenData.userid,
password: hashedPassword,
});
await Token.findOneAndDelete({ token: req.body.token });
res.send({ success: true, message: "Password reset successfull" });
} else {
res.send({ success: false, message: "Invalid token" });
}
} catch (error) {
res.status(500).send(error);
}
});
router.post("/verifyemail", async (req, res) => {
try {
const tokenData = await Token.findOne({ token: req.body.token });
if (tokenData) {
await User.findOneAndUpdate({ _id: tokenData.userid, isVerified: true });
await Token.findOneAndDelete({ token: req.body.token });
res.send({ success: true, message: "Email Verified Successlly" });
} else {
res.send({ success: false, message: "Invalid token" });
}
} catch (error) {
res.status(500).send(error);
}
});
Backend => sendEmail.js :
const nodemailer = require("nodemailer");
const bcrypt = require("bcrypt");
const Token = require("../models/tokenModel");
module.exports = async (user, mailType) => {
try {
const transporter = nodemailer.createTransport({
service: "gmail",
host: "smtp.gmail.com",
port: 587,
secure: true,
auth: {
user: "sh***********th#gmail.com",
pass: "e**************l",
},
});
const encryptedToken = bcrypt
.hashSync(user._id.toString(), 10)
.replaceAll("/", "");
const token = new Token({
userid: user._id,
token: encryptedToken,
});
await token.save();
let mailOptions, emailContent;
if (mailType === "verifyemail") {
emailContent = `<div><h1>Please click on the below link to verify your email address</h1> ${encryptedToken} </div>`;
mailOptions = {
from: "sh************th#gmail.com",
to: user.email,
subject: "Verify Email For MERN Auth",
html: emailContent,
};
} else {
emailContent = `<div><h1>Please click on the below link to reset your password</h1> ${encryptedToken} </div>`;
mailOptions = {
from: "shanshangeeth#gmail.com",
to: user.email,
subject: "Reset Password",
html: emailContent,
};
}
await transporter.sendMail(mailOptions);
} catch (error) {
console.log(error);
}
};
// auth: {
// user: "shanshangeeth#gmail.com",
// pass: "erwsvgtamrplzssl",
// },
Backend => authMiddleware.js :
const jwt = require("jsonwebtoken");
module.exports = async (req, res, next) => {
try {
const token = req.headers["authorization"].split(" ")[1];
jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => {
if (err) {
return res.status(401).send({
message: "Auth failed",
success: false,
});
} else {
req.body.userId = decoded.id;
next();
}
});
} catch (error) {
return res.status(401).send({
message: "Auth failed",
success: false,
});
}
};
Backend => tokenmodel.js :
const mongoose = require("mongoose");
const tokenSchema = new mongoose.Schema(
{
userid: {
type: String,
required: true,
},
token: {
type: String,
required: true,
},
},
{ timestamps: true }
);
const tokenModel = mongoose.model("tokens", tokenSchema);
module.exports = tokenModel;
When I create/register user1 , the verification mail is sent to that email id and he(user1) is being verified successfully and I am able to change password for user1.
After creating user1 , I am creating/registering user2 ,where the verification email is sent to the account .After clicking the link , it's becomes INVALID
Overall , I am only able to create one user who's being verified
In the "verifyemail" route handler is you are trying to access the body of the req which is null, remember that when a user clicks on that URL in the email, a get request is send. The token will then exist in the req.params object, Not req.body.
Try the changes below.
router.get("/verifyemail/:token", async (req, res) => {
try {
const tokenData = await Token.findOne({ token: req.params.token });
if (tokenData) {
await User.findOneAndUpdate({ _id: tokenData.userid, isVerified: true });
await Token.findOneAndDelete({ token: req.params.token });
res.send({ success: true, message: "Email Verified Successlly" });
}

JWT token signup and signin express API

I am trying postman for signup a user, {"firstName": "John", "lastName":"zoe", "email":"aaa#gmail.com", "password":"123465"} but the postman gives me this 500 error: {
"message": "Something went wrong"
},
I could not figure out is my logic wrong, or something is missing, I did not use the validator package, as I am not sure how to use it, is that the problem? can anyone pls help?
here is my code, in the server.js file:
const express = require("express");
const env = require("dotenv");
const { response } = require("express");
const app = express();
const mongoose = require("mongoose");
//routes
const authRoutes = require("./routes/auth");
const adminRoutes = require("./routes/adminauth");
const categoryRoutes = require("./routes/category");
//enviorment variables
env.config();
app.use(express.json());
mongoose
.connect(
`mongodb+srv://${process.env.MONGO_DB_USER}:${process.env.MONGO_DB_PASSWORD}#cluster0.h28xczp.mongodb.net/${process.env.MONGODB_DATABASE}?retryWrites=true&w=majority`
)
.then(() => {
console.log("Database connection established");
});
app.use("/api", authRoutes);
app.use("/api", adminRoutes);
app.use("/api", categoryRoutes);
app.listen(process.env.PORT, () => {
console.log(`server is running at ${process.env.PORT}`);
});
In my routes file:
const express = require("express");
const router = express.Router();
const { signupUser, loginUser } = require("../controller/auth");
const { auth, userMiddleware, adminMiddleware } = require("../middleware/auth");
//login route
router.post("/login", loginUser);
//signup route
router.post("/signup", signupUser);
module.exports = router;
Middleware file:
const jwt = require("jsonwebtoken");
const User = require("../models/user");
exports.auth = (req, res, next) => {
try {
const token = req.header.authorization.split("")[1];
const isCustomAuth = token.length < 500;
let decodeData;
if (token && isCustomAuth) {
decodeData = jwt.verify(token, env.Process.JWT_SECRET);
req.UserId = decodeData?.id;
} else {
decodeData = jwt.decode(token);
req.UserId = decodeData?.sub;
}
next();
} catch (error) {}
};
exports.userMiddleware = (req, res, next) => {
if (req.user.role !== "user") {
return res.status(400).json({ message: "User access denied" });
}
next();
};
exports.adminMiddleware = (req, res, next) => {
if (req.user.role !== "admin") {
return res.status(400).json({ message: "Access denied" });
}
next();
};
In my controller file:
const User = require("../models/user");
const jwt = require("jsonwebtoken");
const bcrypt = require("bcrypt");
exports.loginUser = async (req, res) => {
const { email, password } = req.body;
try {
const existingUser = await User.findOne({ email });
if (!existingUser)
return res.status(400).json({ message: "User does not exists." });
const isPasswordCorrect = await bcrypt.compare(
password,
existingUser.password
);
if (!isPasswordCorrect)
return res.status(400).json({ message: "Invalid credentials." });
const token = jwt.sign(
{ email: existingUser.email, id: existingUser._id },
process.env.JWT_SECRET,
{ expiresIn: "3d" }
);
res.status(200).json({ result: existingUser, token });
} catch (error) {
res.status(500).json({ message: "Something went wrong" });
}
};
exports.signupUser = async (req, res) => {
const { firstName, lastName, email, password, confirmPassword } = req.body;
try {
const existingUser = await User.findOne({ email });
if (existingUser)
return res.status(400).json({ message: "User already exists." });
if (!password == confirmPassword)
return res.status(400).json({ message: "Password don't match" });
const hashedPassword = await bcrypt.hash(password, 12);
const result = await User.create({
email,
password: hashedPassword,
firstName,
lastName,
});
const token = jwt.sign(
{ email: result.email, id: result._id },
process.env.JWT_SECRET,
{ expiresIn: "3d" }
);
res.status(200).json({ result, token });
} catch (error) {
res.status(500).json({ message: "Something went wrong" });
}
};
My user model file:
const mongoose = require("mongoose");
const bcrypt = require("bcrypt");
const userSchema = new mongoose.Schema(
{
firstName: {
type: String,
required: true,
trim: true,
},
lastName: {
type: String,
required: true,
trim: true,
},
email: {
type: String,
required: true,
trim: true,
unique: true,
},
password: {
type: String,
required: true,
},
id: {
type: String,
},
},
{ timestamps: true }
);
module.exports = mongoose.model("User", userSchema);
In the middleware, this line contains a wrong reference to JWT_SECRET.
decodeData = jwt.verify(token, env.Process.JWT_SECRET);
Should be
decodeData = jwt.verify(token, process.env.JWT_SECRET);
The application throws an unhandled promise rejection error when trying to connect DB, which means it can operate without a DB connection and then throw that error.
So, to handle that, you can rewrite your code to this.
mongoose.connect('mongodb://localhost:27017/usersdb', // change with your db url
{
useNewUrlParser: true,
useUnifiedTopology: true
}
)
.then(() => {
app.use("/api", authRoutes);
app.listen(process.env.PORT, () => {
console.log("Server has started on port!", process.env.PORT)
})
})
.catch(() => { throw new Error(("Connection error")) });
Also, I successfully ran and tested your application on my local machine. Here is a GitHub link; you can compare.
https://github.com/nairi-abgaryan/express-auth

I am getting this error TypeError: Cannot read properties of undefined (reading 'header') , I am trying to middleware to get users data

I have created a middleware folder inside it I have created fetchuser.js
This is my fetchuser.js code, I have created getuser endpoint so that I can authenticate the user.
I have created a new post request in my thunderclient, but because of this error I am not able to do anything
...
const jwt = require('jsonwebtoken');
const JWT_SECRET = "Saurabhisgood$ouy";
const fetchuser = (req, res, next) => {
// Get the user from jwt token and id to req object
const token = req.header('auth-token');
if (!token) {
res.status(401).send({ error: "Please authenticate using a valid token" })
}
try {
const data = jwt.verify(token, JWT_SECRET)
req.user = data.user;
next();
} catch (error) {
res.status(401).send({ error: "Please authenticate using a valid token" })
}
}
module.exports = fetchuser();
...
This is auth.js file
...
const express = require('express');
const User = require('../models/User');
const router = express.Router();
const { body, validationResult } = require('express-validator');
const bcrypt = require('bcryptjs');
const JWT_SECRET = "Saurabhisgood$ouy";
const jwt = require('jsonwebtoken');
const fetchuser = require('../middleware/fetchuser');
// Create a user using : POST "/api/auth/createuser". Doesn't require auth. Dosen't require login
router.post('/createuser', [
body('name', 'Name should be atleast 3 characters').isLength({ min: 3 }),
body('email', 'Email should be unique').isEmail(),
body('password', 'Password must be atleast 5 characters').isLength({ min: 5 }),
], async (req, res) => {
// If there are errors then you will get bad request
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// Check whether the user with the same email exists
try {
let user = await User.findOne({ email: req.body.email });
if (user) {
return res.status(400).json({ error: "The user with this email already exists" })
}
const salt = await bcrypt.genSalt(10);
const secPass = await bcrypt.hash(req.body.password, salt);
// Create a new user
user = await User.create({
name: req.body.name,
email: req.body.email,
password: secPass
});
const data = {
user: {
id: user.id
}
}
const authToken = jwt.sign(data, JWT_SECRET);
// console.log(jwtData);
// res.json(user);
res.json({authToken});
} catch (error) {
console.error(error.message);
res.status(500).send("Internal server error")
}
})
// Authenticate a user using : POST "/api/auth/login". Doesn't require auth. Dosen't require login
router.post('/login', [
body('email', 'Email should be unique').isEmail(),
body('password', 'Password cannot be blank').exists(),
], async (req, res) => {
// If there are errors then you will get bad request
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
};
const { email, password } = req.body;
// Check whether the user with the same email exists
try {
let user = await User.findOne({email});
if (!user) {
return res.status(400).json({ error: "Please enter the valid credentials" })
}
const passwordComapare= await bcrypt.compare(password, user.password);
if (!passwordComapare) {
return res.status(400).json({ error: "Please enter the valid credentials" })
}
const data = {
user: {
id: user.id
}
}
const authToken = jwt.sign(data, JWT_SECRET);
// console.log(jwtData);
// res.json(user);
res.json({authToken});
} catch (error) {
console.error(error.message);
res.status(500).send("Internal server error")
}
})
// Get details of logged in user using : POST "/api/auth/getuser". Require login
router.post('/getuser', fetchuser , async (req, res) => {
try {
userId= req.user.id;
const user= await User.findById(userId).select("-password");
res.send(user);
} catch (error) {
console.error(error.message);
res.status(500).send("Internal server error")
}
})
module.exports = router
...
You invoking the middleware automatically, change:
module.exports = fetchuser();
to:
module.exports = fetchuser;

TypeError: Cannot read property 'jwtoken' of undefined at Authenticate

I am trying to authenticate the user using jwt and found this error. This is a MERN project and I had to verify the user whose data I have stored in MongoDb before showing a secret page.
Other errors which VSCode is highlighting are:
1.When I hover on ._id (authentication.js)
const rootUser=await User.findOne({_id:verifyToken._id,"tokens.token":token})
Property '_id' does not exist on type 'string | JwtPayload'.
2.When I hover on req.rootUser(app.js)
res.send(req.rootUser)
Property 'rootUser' does not exist on type 'Request<{}, any, any, ParsedQs, Record<string, any>>
My code looks as follows:
app.js
const mongoose = require('mongoose')
const dotenv = require('dotenv')
const bcrypt = require('bcryptjs')
const jwt=require('jsonwebtoken')
const app = express()
const router = express.Router();
const port = 5000
const authenticate=require("./middleware/authenticate")
dotenv.config({ path: './config.env' })
const DB = process.env.DATABASE;
app.use(express.json());
const User = require('./model/userSchema')
mongoose
.connect(DB, {
useUnifiedTopology: true,
useNewUrlParser: true,
})
.then(() => console.log('Database connected.'))
.catch(err => console.log(err));
app.get('/', (req, res) => {
res.send('Hello World!')
console.log("hey")
})
app.post('/register', async (req, res) => {
const { name, email, work, phone, password, cpassword } = req.body;
if (!name || !email || !work || !phone || !password || !cpassword) {
return res.status(422).json({ error: "Form Not Properly Filled" });
}
try {
const userExist = await User.findOne({ email: email })
if (userExist) {
return res.status(422).json({ error: "Email ALready Exists" })
}
else if (password != cpassword) {
return res.status(422).json({ error: "Password does not match" })
}
else {
const user = new User({ name, email, work, phone, password, cpassword })
await user.save()
res.status(201).json({ message: "user registered successfully" })
}
} catch (error) {
console.log(error);
}
})
//login route
app.post('/signin', async (req, res) => {
try {
let token;
const { email, password } = req.body;
if (!email || !password) {
return res.status(400).json({ error: "Please fill the data correctly" })
}
const userLogin = await User.findOne({ email: email })
console.log(userLogin);
if (userLogin) {
const isMatch = await bcrypt.compare(password, userLogin.password)
token = await userLogin.generateAuthToken();
console.log(token)
res.cookie("jwtoken",token,{
expires:new Date(Date.now()+25892000000),
httpOnly:true
})
if (!isMatch) {
res.status(400).json({ error: "Invalid Credentials" })
}
else {
res.status(200).json({ message: "Login Success" })
}
}
else {
res.status(400).json({ error: "Invalid Credentials" })
}
} catch (error) {
console.log(error)
}
})
//about page request
app.get('/about',authenticate, (req, res) => {
console.log("About")
res.send(req.rootUser)
})
app.get('/forget', (req, res) => {
res.cookie("harsh","test")
res.send('Forget World!')
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
authenticate.js
const User=require("../model/userSchema")
const Authenticate=async (req,res,next)=>{
try {
console.log(req.cookies)
const token=req.cookies.jwtoken;
console.log("below")
const verifyToken =jwt.verify(token,process.env.SECRET_KEY)
console.log(verifyToken)
const rootUser=await User.findOne({_id:verifyToken._id,"tokens.token":token})
if(!rootUser){
throw new Error("User Not Found")
}
req.token=token;
req.rootUser=rootUser;
req.userID=rootUser._id;
next();
} catch (error) {
res.status(401).send('Unauthorized : No token provided')
console.log(error)
}
}
module.exports=Authenticate;
userSchema.js
const mongoose=require('mongoose')
const bcrypt=require('bcryptjs')
const jwt=require('jsonwebtoken')
const userSchema=new mongoose.Schema({
name:{
type:String,
required:true,
},
email:{
type:String,
required:true,
},
phone:{
type:String,
required:true,
},
work:{
type:String,
required:true,
},
password:{
type:String,
required:true,
},
cpassword:{
type:String,
required:true,
},
tokens:[
{
token:{
type:String,
required:true,
}
}
]
})
userSchema.pre('save' , async function(next){
console.log("inside hash")
if(this.isModified('password')){
this.password=await bcrypt.hash(this.password,12)
this.cpassword=await bcrypt.hash(this.cpassword,12)
}
next();
})
userSchema.methods.generateAuthToken = async function(){
try {
let token =jwt.sign({_id:this._id},process.env.SECRET_KEY)
this.tokens=this.tokens.concat({token : token})
await this.save();
return token
} catch (error) {
console.log(error)
}
}
const User=mongoose.model('USER',userSchema);
module.exports=User;
1. GENERATE JWT TOKEN WHEN USER LOGIN
Generate Token and Send this token with a response...
router.post("/login", async (req, res) => {
try {
// checking username
const user = await User.findOne({ email: req.body.email });
!user && res.status(401).json("Wrong Username");
// checking password
const bytes = CryptoJS.AES.decrypt(user.password, process.env.SECRET_KEY);
const originalPassword = bytes.toString(CryptoJS.enc.Utf8);
// If password not match return respond
originalPassword !== req.body.password &&
res.status(401).json("Wrong Password");
// Creating Json Web Token
const accessToken = jwt.sign(
{ id: user._id, isAdmin: user.isAdmin },
process.env.SECRET_KEY,
{ expiresIn: "5d" }
);
// stop sending password to respond
const { password, ...info } = user._doc;
// Returning User(info) , also sending accessToken
res.status(200).json({ ...info, accessToken });
} catch (err) {
res.status(500).json(err);
}
});
2. VERIFY TOKEN MIDDLEWARE
Create this verify token function use as a MIDDLEWARE in your routes...
const jwt = require("jsonwebtoken");
function verify(req, res, next) {
const authHeader = req.headers.token;
if (authHeader) {
const token = authHeader.split(" ")[1];
jwt.verify(token, process.env.SECRET_KEY, (err, user) => {
if (err) res.status(403).json("Token is not valid");
req.user = user;
next();
});
} else {
return res.status(402).json("You are not authorized");
}
}
module.exports = verify;
3. VERIFY-IN ROUTES AS AN MIDDLEWARE
const verify = require("../verifyToken");
// CREATE
router.post("/", verify, async (req, res) => {
if (req.user.isAdmin) {
const newList = new List(req.body);
try {
const savedList = await newList.save();
res.status(201).json(savedList);
} catch (error) {
res.status(500).json(err);
}
} else {
res.status(403).json("You are not allowed!");
}
});
// DELETE
router.delete("/:id", verify, async (req, res) => {
if (req.user.isAdmin) {
try {
await List.findByIdAndDelete(req.params.id);
res.status(201).json("The list has been deleted");
} catch (err) {
res.status(500).json(err);
}
} else {
res.status(403).json("You are not allowed!");
}
});
CONCLUSION:-
Create a token with jwt.sign when user login...
Create a verify function in the root directory export this function...
Require this function in routes file use as a middleware...

Resources