User info in payload interchanging with other Users?
See original GitHub issueHi Team,
I’ve noticed a quite strange issue on our Android app, Some of the users are seeing someone else’s profile. The api uses jsonwebtoken for authorization.
The implementation is quite similar to this article: https://scotch.io/tutorials/authenticate-a-node-js-api-with-json-web-tokens
We have a middleware which intercept requests and check if the auth token is valid, if it is valid then adds the payload to the request. Code
var router = express.Router();
// ------- ROUTE MIDDLEWARE START ----//
router.use(function(req, res, next) {
//check header or url parameters or post parameters for token.
var token = req.body.token || req.query.token || req.headers['x-access-token'];
// decode token
if (token) {
// verifies the scret and checks expiration
jwt.verify(token, app.get('superSecret'), function(err, decoded) {
if (err) {
res.status(400).json({
success: false,
message: 'Session Expired, Please Relogin.'
});
// return next(); //dont send next() here as we return the response needed.
return;
} else {
// if everything is good, save to request for use in other routes
//var decoded = jwt.decode(token, {complete: true});
//req.doc = decoded.payload;
req.doc = decoded;
// console.log(decoded);
return next();
}
});
} else {
// if there is no token
// return an error
return res.status(403).send({
success: false,
message: 'Please Login to access this Service.' //no token provided
})
//dont send next here if no token is provided.
}
});
// ------- ROUTE MIDDLEWARE END ----//
Then in Endpoint implementation for get profile.
router.get('/profile', function(req, res) {
user.findOne({
_id: req.doc._id
}, function(err, data) {
if (err) {
console.error(err);
return res.status(400).send({
message: err.message,
status: false
});
}
if (data) {
data.user_password = null;
}
return res.send(data);
});
});
module.exports = router;
The above code implemetation is for User module, router is exported by module.exports
and in main app.js
var express = require('express');
var app = module.exports = express();
var port = process.env.PORT || 3000; //used to create, sign and verify token
mongoose.connect(config.database); // connect to our database
app.set('superSecret', config.secret);
app.set('config',config);
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json({}));
//adding all the modules or routes we have
app.use('/user',require('./routes/user')); //pass router object of user module
app.use('/admin',require('./routes/panel_user')); //pass router object of panel_user module
app.use('/news',require('./routes/news')); //pass router object of news module
app.listen(port);
I have tried digging into our implementation but can not find something wrong app was running good from an year, no one reported such issue recently 2 users have reported that they are seeing someone else’s profile. I’m not able to reproduce the issue on my own, it could have been payload is being mixed of 2 different authtoken’s signed by jwt due to whatever reason? or server load?
We are refreshing the token on each app start if user’s token is not expired he is allotted a new one on app start with 15 days expiration time, old token is just discarded and not added into any blacklist or so and if his token is expired he is expected to login again in that case.
Issue Analytics
- State:
- Created 6 years ago
- Comments:9 (3 by maintainers)
Hi Guys
I see every now and then people landing on this thread and reaching out to me for a solution. Instead of reverting individually, I decided to share the workaround here.
The solution is pretty simple, instead of req object, add the decoded doc or any user information to the res.locals for example instead of req.doc = decoded;
use res.locals.doc = decoded;
The request object sometimes behaves odd, while res.locals is the right way to go for such use cases, where we need to save some data related to particular request.
Hello, not a maintainer but just speculating, what you are describing could be happening when generating/signing the jwt if you are using an object reference to create the jwt user instead of regenerating it using a function or new object each time. Could you add you section for login?