I am making a web application using nodejs and angular cli I'm using JWT to authenticate my login function . But when I process it threw this error
Error: Expected "payload" to be a plain object. at validate (D:\Mean_Projects\meanauthapp\node_modules\jsonwebtoken\sign.js:34:11) at validatePayload (D:\Mean_Projects\meanauthapp\node_modules\jsonwebtoken\sign.js:56:10) at Object.module.exports [as sign] (D:\Mean_Projects\meanauthapp\node_modules\jsonwebtoken\sign.js:108:7) at User.comparePassword (D:\Mean_Projects\meanauthapp\routes\users.js:86:27) at bcrypt.compare (D:\Mean_Projects\meanauthapp\models\user.js:53:9) at D:\Mean_Projects\meanauthapp\node_modules\bcryptjs\dist\bcrypt.js:297:21 at D:\Mean_Projects\meanauthapp\node_modules\bcryptjs\dist\bcrypt.js:1353:21 at Immediate.next [as _onImmediate] (D:\Mean_Projects\meanauthapp\node_modules\bcryptjs\dist\bcrypt.js:1233:21) at runCallback (timers.js:785:20) at tryOnImmediate (timers.js:747:5) at processImmediate [as _immediateCallback] (timers.js:718:5)
Here my passport code
const JwtStrategy= require('passport-jwt').Strategy;
const ExtractJwt=require('passport-jwt').ExtractJwt;
const User= require('../models/user');
const config=require('../config/database');
module.exports=function(passport){
let opts={};
opts.jwtFromRequest=ExtractJwt.fromAuthHeader();
opts.secretOrKey=config.secret;
opts.issuer = 'accounts.examplesoft.com';
opts.audience = 'yoursite.net';
passport.use(new JwtStrategy(opts,(jwt_payload,done)=>{
console.log(jwt_payload);
User.getUserById(jwt_payload._doc._id,(err,user)=>{
if(err){
return done(err,false);
}
if(user){
return done(null,user);
}
else{
return done(null,false);
}
});
}));
}
My code for authenticate and get profile
// Authenticate
router.post('/authenticate', (req, res, next) => {
const username = req.body.username;
const password = req.body.password;
User.getUserByUsername(username, (err, user) => {
if(err) throw err;
if(!user){
return res.json({success: false, msg: 'User not found'});
}
User.comparePassword(password, user.password, (err, isMatch) => {
if(err) throw err;
if(isMatch){
const token = jwt.sign(user, config.secret, {
expiresIn: 604800 // 1 week
});
res.json({
success: true,
token: 'JWT '+token,
user: {
id: user._id,
name: user.name,
username: user.username,
email: user.email
}
});
} else {
return res.json({success: false, msg: 'Wrong password'});
}
});
});
});
// Profile
router.get('/profile', passport.authenticate('jwt', {session:false}), (req, res, next) => {
res.json({user: req.user});
});
It's very simple, if the user comes from database (mongo) then simply do
user.toJSON()
, if the user comes from any other source then simply doJSON.stringify(user)
.I had this problem as well, with a returned user from mongoose, just add
toJSON()
ortoObject()
will fix the issue, but what happens if your user is not always coming from mongoose?You will get a
if you try to do this on a plain object.
If your user is coming from different sources and you don't know if it will be a plain object or not, you can solve it like this:
this is clearly mentioned in the migration doc of passport-jwt
that they have removed the
ExtractJwt.fromAuthHeader()
from version 2 and 3 and also to use the new methodExtractJwt.fromAuthHeaderAsBearerToken()
or one of like that in place of old method. for compelte reference visitFrom your log there is the issue
so here four thing need to be updated in your code
@every Bit
First in package.json file
Change the version to latest by using * or version no like this by going to project directory and run the command
or write in the file and run the commadn
Second change this line of your code in authenticate method
Third in the passport code change the old method
to new one, from the doc reference you need to use this method
opts.jwtFromRequest=ExtractJwt.fromAuthHeaderWithScheme('jwt');
and fourth change this
This solution will work on latest version's
only change the version of your passport-jwt in package.json to 1.x.x (x is the nuber here )of your choise of lower version then 2,
by moving to project folder and runing the command
npm install
the only thing you need to check is data in the payload_jwt,it will be inside the second layer so please check the jwt_payload.
ok you are all set to go you had already handled
User.getUserById(jwt_payload._doc._id,(err,user)=>{
It fails at the line
With error "Expected "payload" to be a plain object"
Your
user
object is initialized here:Which I assume is
mongoosejs
object, which contains many methods and is not "serializable". You could handle this by passing a plain object, by either using.lean()
frommongoose
or plaintoJSON
method: