How can I fix : "Cannot read properties of undefined( reading 'role')" I believe its a mongodb/mongoose issue. How can I fix database request issue?

Viewed 39

I am currently getting problems reading role on my postman POST request on backend nodejs express. I was wondering how would i go about fixing this?

below is the route for authentication in my middleware/auth.js

 exports.isAuthenticatedUser = catchAsyncErrors(async (req, res, next) => {

    const { token } = req.cookies

    if (!token) {
        return next(new ErrorHandler('Login first to access this resource.', 401))
    }

    const decoded = jwt.verify(token, process.env.JWT_SECRET)
    req.user = await User.findById(decoded.id);

    next()
})

// Handling users roles
exports.authorizeRoles = (...roles) => {
    return (req, res, next) => {
        if (!roles.includes(req.user.role)) {
            return next(
                new ErrorHandler(`Role (${req.user.role}) is not allowed to acccess this resource`, 403))
        }
        next()
    }
}

I have added in extra information. Hopefully this helps clear up some missing background info. But the ideas is to show you where ```decoded.id`` comes from (getJwtToken). which by the way is used in the registration process of user accounts. which I also share at the bottom.

addition to models/users.js :

const mongoose = require('mongoose');
const validator = require('validator');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken')
const crypto = require('crypto')

const userSchema = new mongoose.Schema({
    name: {
        type: String,
        required: [true, 'Please enter your name'],
        maxLength: [30, 'Your name cannot exceed 30 characters']
    },
    email: {
        type: String,
        required: [true, 'Please enter your email'],
        unique: true,
        validate: [validator.isEmail, 'Please enter valid email address']
    },
    password: {
        type: String,
        required: [true, 'Please enter your password'],
        minlength: [6, 'Your password must be longer than 6 characters'],
        select: false
    },
    avatar: {
        public_id: {
            type: String,
            required: true
        },
        url: {
            type: String,
            required: true
        }
    },
    role: {
        type: String,
        default: 'user'
    },
    createdAt: {
        type: Date,
        default: Date.now
    },
    resetPasswordToken: String,
    resetPasswordExpire: Date

})

userSchema.methods.getJwtToken = function () {
    return jwt.sign({ id: this._id }, process.env.JWT_SECRET, {
        expiresIn: process.env.JWT_EXPIRES_TIME
    });
}

controllers/authController.js

exports.registerUser = catchAsyncErrors(async (req, res, next) => {

    const result = await cloudinary.v2.uploader.upload(req.body.avatar, {
        folder: 'avatars',
        width: 150,
        crop: "scale"
    })

    const { name, email, password } = req.body;

    const user = await User.create({
        name,
        email,
        password,
        avatar: {
            public_id: result.public_id,
            url: result.secure_url
        }
    })

    sendToken(user, 200, res)

})

and your utils/jwtToken.js

const sendToken = (user, statusCode, res) => {

    // Create Jwt token
    const token = user.getJwtToken();

    // Options for cookie
    const options = {
        expires: new Date(
            Date.now() + process.env.COOKIE_EXPIRES_TIME * 24 * 60 * 60 * 1000
        ),
        httpOnly: true
    }


    res.status(statusCode).cookie('token', token, options).json({
        success: true,
        token,
        user
    })

}

module.exports = sendToken;
1 Answers

The error is due to your user to be undefined. You should handle that case, but if you don't want for any reason you can just check it is not null using req.user?.role:

exports.authorizeRoles = (...roles) => {
return (req, res, next) => {
    if (!roles.includes(req.user?.role)) {
        return next(
            new ErrorHandler(`Role (${req.user?.role}) is not allowed to acccess this resource`, 403))
    }
    next()
}
}

In this case, if the user is not defined the role will be undefined too (returning the same error of Role (${req.user.role}) is not allowed to acccess this resource)

NULL CHECK USER

exports.authorizeRoles = (...roles) => {
if (!req.user) //throw error (user doesn't exist in db)
return (req, res, next) => {
    if (!roles.includes(req.user.role)) {
        return next(
            new ErrorHandler(`Role (${req.user.role}) is not allowed to acccess this resource`, 403))
    }
    next()
}
}
Related