On a successful signup of a user I am currently seeing a mostly empty page with the text undefined. Redirecting to /app at the top.
UPDATE: I should also mention that after form submittal I am redirected to /users. So on /users I see the text mentioned above.
I think it is because of the req.redirect call being within the user.save callback but I am not sure what the fix is.
I am using mongoose for the ORM.
var User = require('../models/user');
module.exports = function(app) {
app.post('/users', function(req, res, next) {
var user = new User({
email: req.body.email,
password: req.body.password
});
user.save(function(err) {
if (err)
res.send(412, {message: err});
else
req.login(user, function(err) {
if (err !== undefined) return next(err);
res.redirect('/app', {
email: user.email,
id: user._id
});
});
});
});
};
It turns out that the req.login call has to be contained in a password.authenticate callback. The example on the site left that part out.
user.save(function(err) {
if (err)
res.send(412, {message: err});
else
passport.authenticate('local', function(err, user) {
if (err) { return next(err) }
if (!user) { return res.redirect('/login') }
req.login(user, function(err) {
if (err) { return next(err); }
return res.redirect('/app', { email:user.email, id:user._id });
});
})(req, res, next);
});
Related
This post request creates a new user account and saves a test score data point for a user.
~1/20 users or so run into an error and are redirected back to the previous page thus losing their results.
I have been unable to replicate the error or see any errors in the logs.
Looking for advice on how to change my error handling and or any insight to why this may be occurring.
Thank you!
router.post("/test", function(req, res){
User.findOne({username: req.body.username}, function(err, existingUser) {
console.log('user exists:' + existingUser)
if (err) {
return done(err);
}
if (!existingUser) {
var newUser = new User({username: req.body.username});
User.register(newUser, req.body.password, function(err, user){
user.testscore = req.body.testscore;
user.save()
if(err){
req.flash("error", err.message);
console.log(err)
res.redirect('back')
return res.render("register");
}
passport.authenticate("local")(req, res, function(){
res.redirect("/thank-you");
});
});
You can use try-catch along with async-await for error handling. I would write the code like this.
router.post('/test', async (req, res) => {
try {
const user = await User.findOne({username: req.body.username})
if (!user) {
let newUser = new User({username: req.body.username});
// If User.register returns promise then here also you can use await like above.
// If any error occurs catch block will catch it and show the error.
User.register(newUser, req.body.password, function(err, user) {
user.testscore = req.body.testscore;
user.save()
if(err) {
req.flash("error", err.message);
console.log(err)
res.redirect('back')
return res.render("register");
}
passport.authenticate("local")(req, res, function() {
res.redirect("/thank-you");
});
});
}
} catch (err) {
console.error(err.message)
}
})
Hope it helps to solve your problem.
I'm using PassportJS. I'm trying to let users edit their email address if needed. This is the code I have which is currently not working.
Any advice? Thank you!
app.post("/editprofile", middleware.isLoggedIn, function(req, res, next){
User.update({ id: req.session.passport.user }, {
email: req.body.email,
}, function(err, user) {
if (err) return next(err);
User.findById(req.user._id, function(err, user) {
if (err) return next(err);
console.log(err)
return res.render('landing.ejs', {
user:user
});
});
});
});
Consider using this and every thing will be fine
app.post("/editprofile", middleware.isLoggedIn, function(req, res, next){
User
.findOneAndUpdate({ _id: request.session.passport.user }, req.body.email)
.exec(function(err, user) {
if (err) return res.render(/* Your error template here */, {
err: err.message
};
return res.render('landing.ejs', {
user: user
});
});
}
}
Hope this helps!
I'm developing a mean application with passport, and I'm running through this issue:
I have a LocalStrategy to log on the user based on the application database. I need, however to login the user simultaneously on another service with possible multiple accounts. The thing is, once I route to authorize these logins, and set the variables to req.account, I cannot access them in other routes. Note that I can get the data I want, I just want to access it from somewhere other than this route, like req.user. I will post some of my code to clarify the situation.
Local Login route
app.post('/login', function (req, res, next) {
passport.authenticate('local-login', function (err, user) {
if (err)
return next(err);
if (!user)
return res.status(400).json({status: 'Invalid Username'});
req.login(user, function (err) {
if (err)
return next(err);
res.status(200).json({status: 'User successfully authenticated'});
});
})(req, res, next);
});
Local login passport config
passport.use('local-login', new LocalStrategy(function (user, pswd, done) {
User.findOne({'username': user}, function (err, user) {
if (err)
return done(err);
if (!user || !user.validPassword(pswd))
return done(null, false);
return done(null, user);
});
}));
The other service passport config
passport.use('other-login', new OtherStrategy(function (docs, done) {
if (docs.length === 0)
return done(null, false);
var accounts = [];
var user, pswd, data;
var counter = docs.length;
for (var i = 0; i < docs.length; i++) {
user = docs[i]._id;
pswd = docs[i].password;
request.post(<serviceurl>, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: qs.stringify({
grant_type: 'password',
username: user,
password: pswd,
client_id: process.env.API_KEY
})
}, function (err, res, body) {
if (err)
return done(err);
data = JSON.parse(body);
data.username = docs[docs.length - counter]._id;
accounts.push(data);
counter--;
if (counter === 0)
return done(null, accounts);
});
}
}));
Other Service route
router.get('/otherservice', passport.authorize('other-login', {}) , function (req, res) {
console.log(req.account);
res.sendStatus(200);
});
Other Service authentication (from custom Strategy)
ServiceStrategy.prototype.authenticate = function (req) {
var self = this;
var id = req.user.master_id || req.user.id;
Service.find({master_id: id}, function (err, docs){
if (err)
return self.error(err);
function verified(err, data, info) {
if (err) { return self.error(err); }
if (!data) { return self.fail(info); }
self.success(data, info);
}
try {
if (self._passReqToCallback) {
self._verify(req, docs, verified);
} else {
self._verify(docs, verified);
}
} catch (ex) {
return self.error(ex);
}
});};
I found the solution! On the User Model, I added an accounts property to store the data returned on the authorization. Then, on the authorization route, I updated the user with this info, and saved. It wasn't that hard at all.
app.post('/api/login', function (req, res, next) {
passport.authenticate('local-login', function (err, user) {
if (err)
return next(err);
if (!user)
return res.status(400).json({status: 'Invalid Username'});
req.login(user, function (err) {
if (err)
return next(err);
var id = req.user.master_id || req.user.id;
Service.findOne({master_id: id}, function (err, doc) {
if (doc == null)
res.status(200).json({
status: 'User successfully authenticated',
accounts: false
});
else
return next();
});
});
})(req, res, next);
}, passport.authorize('other-login', {}), function (req, res) {
var accounts = req.account;
var user = req.user;
user.accounts = accounts;
user.save(function (err, newUser) {
if (err)
throw err;
res.status(200).json({
status: 'User sucessfully authenticated',
accounts: true
});
})
});
In my nodejs API app I have this route:
router.post('/startuserseries', function(req, res, next){
if(!req.body.username){
return res.status(400).json({message: 'Geen username'});
}
User.findOne({ 'username': req.body.username}, function(err, foundUser){
if(err)
return next(err);
if (foundUser) // check the value returned for undefined
{
foundUser.isdoingchallenges = true;
foundUser.save(function (err) {
if(err) {
console.error('ERROR!');
}
});
}
});
});
When I call this route in postman, the request never ends.
I have tried to use PUT but also didn't work, I tried various structures of code but neither worked.
This request will not finish because it doesn't write a response command on server.
You should solve easily this problem like below:
router.post('/startuserseries', function(req, res, next){
if(!req.body.username){
return res.status(400).json({message: 'Geen username'});
}
User.findOne({ 'username': req.body.username}, function(err, foundUser){
if(err)
return next(err);
if (foundUser) // check the value returned for undefined
{
foundUser.isdoingchallenges = true;
foundUser.save(function (err) {
if(err) {
res.json(err);
}
});
}
res.send(200);
// or your specific result json object
// res.json({"error":false,"message":"completed"})
});
});
Every time i refresh a html page at route 'localhost:8080/' or login a user I will get this Error: Can't set headers after they are sent. As far as I know this problem happens due to callbacks that are accidentally called twice. The app doesn't crash or anything, its just keep logging the same error on the console.
Here's the code.
var User = require('../models/user');
var Story = require('../models/story');
var jwt = require('jsonwebtoken');
var config = require('../../config');
var superSecret = config.secret;
module.exports = function(app, express) {
// creating our first router
var apiRouter = express.Router();
// signup a user
apiRouter.post('/signup', function(req, res) {
var user = new User({
name: req.body.name,
username: req.body.username,
password: req.body.password
});
user.save(function(err) {
if(err) res.send(err);
res.json({ message: 'User has been created!' });
});
});
apiRouter.get('/users', function(req, res) {
User.find({}, function(err, users) {
if(err) res.send(err);
res.json(users);
});
});
// user login
apiRouter.post('/login', function(req, res) {
User.findOne({
username: req.body.username
}).select('name username password').exec(function(err, user) {
if(err) throw err;
if(!user) {
res.json({ message: "Wrong User" });
} else if(user) {
var validPassword = user.comparePassword(req.body.password);
if(!validPassword) {
res.json({ message: "Invalid Password" });
} else {
var token = jwt.sign({
id: user._id,
name: user.name,
username: user.username
}, superSecret, {
expiresInMinute: 1440
});
// return all the sucess
res.json({
success: true,
message: "Successfully login and token created!" + token.name,
token: token
});
};
}
});
});
// write a middleware for login
// A middleware for login user only, once a user has logged in , he can enter other links below
apiRouter.use(function(req, res, next) {
// do logging
console.log("Somebody just came to our app!");
var token = req.body.token || req.param('token') || req.headers['x-access-token'];
// check if token exist
if(token) {
jwt.verify(token, superSecret, function(err, decoded) {
if(err) {
res.status(403).send({ success: false, message: 'Failed to authenticate user' });
} else {
// if everything is good save request for use in other routes
req.decoded = decoded;
next();
}
});
} else {
res.status(403).send({ success: false, message: 'No token provided' });
}
});
apiRouter.route('/')
.post(function(req, res) {
var story = new Story({
user: req.decoded.id,
content: req.body.content
});
story.save(function(err, stor) {
if(err) res.send(err)
console.log(stor);
res.json(stor);
});
})
.get(function(req, res) {
Story.find({ user: req.decoded.id }, function(err, story) {
if(err) res.send(err);
res.json(story);
});
});
apiRouter.get('/me', function(req, res) {
res.send(req.decoded.name);
});
apiRouter.route('/:user_id')
.get(function(req, res) {
User.findById(req.params.user_id, function(err, user) {
if(err) res.send(err);
res.json(user);
});
})
.put(function(req, res) {
User.findById(req.params.user_id, function(err, user) {
if(err) res.send(err);
if(req.body.name) {
user.name = req.body.name;
}
if(req.body.username) {
user.username = req.body.username;
}
if(req.body.password) {
user.password = req.body.password;
}
user.save(function(err) {
if(err) res.send(err);
res.json({ message: "User updated" });
});
});
});
return apiRouter;
}
You are sending a response twice when an error occurs:
if (err) res.send(err);
res.json(foo);
Replace that with:
if (err) { res.send(err); return; }
res.json(foo);