I do not want a redirect in my sign-up route, it is a two stage process (the way I currently have it figured out), so I would like to submit the first form, save to db with ajax and return something, and then show the second form to complete sign up. The post route works, but the function does not run
router.route('/register')
.post((req, res, next) => {
console.log('this bit here works');
passport.authenticate('local-signup', function(error, user) {
console.log('it's here that nothing happens');
if(error) {
return res.status(500).json(error);
}
return res.json(user); //this is what I want to return;
})
})
Does passport only work with the one post call?
passport.authenticate() is an Express middleware, not a regular function.
As per the fine manual (search for "Custom Callback"), it should be used like this:
router.route('/register').post((req, res, next) => {
console.log('this bit here works');
passport.authenticate('local', function(error, user, info) {
console.log("it's here that something should happen now.");
if (error) {
return res.status(500).json(error);
}
return res.json(user);
})(req, res, next);
})
FWIW, user may not necessarily be a proper object (if authentication failed, for instance).
Related
It is the same login route.
Just 2 different approaches.
First route
router.post('/login', passport.authenticate('local',{session:false}),async (req,res) => {
console.log("\n\n\n ------------------------222222")
console.log(req.user);
});
and the request object has the user & is displayed.
Whereas in the second route
router.post('/login', (req, res, next) => {
passport.authenticate('local', async (err, user, info) =>{
if(err){
console.log(err);
}
console.log("\n\n\n ------------------------")
console.log(req.user); //undefined
if(user){
// it works here
}
else{
res.status(422).json(info);
}
})(req, res, next);
});
console.log(req.user); shows undefined.
but the user has the user details fetched from the mongo db.
Can someone explain me please.
In the second function, you get the user in the user key. However, you ll have to add it to req object. It can be done like this
if(user){
// it works here
req.user = user;
}
In the first case, it is already added to the req object since it has already executed passport.authenticate before getting into the next async function.
If you print the req.user after the if else, it will give you the exact details.
I think that I know why we use next() in expressjs in theory: :)
In fact, the routing methods can have more than one callback function as arguments. With multiple callback functions, it is important to provide next as an argument to the callback function and then call next() within the body of the function to hand off control to the next callback.
But in practice I can't get it.
app.get('/project', (req, res, next) => {
con.query("SELECT * FROM issues", (err, result) => {
if (err) throw err;
res.send(result);
})
next()
console.log("NEVER HERE");
});
This is situation where this code do not work.
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
But if I put next() right bellow res.send(result); and remove this one above console.log('NEVER HERE'); statement it works perfectly.
Also if I remove next() on both places it works well.
And what I noticed is if I use console.log(result) instead of res.send(result) it works no metter where next() callback is.
My main question is why one next() "makes troubles" to other one, when they are used together with res.send().
I'm new to express and also with mysql, thank you in advance. :)
You are not supposed to use both res.send and next
The purpose of next is to pass control to another middleware but when you respond to the request using res.send(...) there's no reason to that.
Simple example when you would use next:
app.get('/admin', function authMiddleware(req, res, next){
// user must be logged in and be an admin to access this route
if (req.user && req.user.isAdmin)
next(); // this will pass control to the handler function bellow
else // respond with 401 error
res.status(401).send('unauthorized');
}, function handler(req, res){
// only get here when user is admin
res.render('admin');
});
Your example should look like this, you don't need to care about next at all:
app.get('/project', (req, res) => {
con.query("SELECT * FROM issues", (err, result) => {
// don't throw, just respond appropriately
//if (err) throw err;
if (err)
res.status(500).send('error occured');
else
res.send(result);
});
// calling `next` here doesn't make any sense unless you pass an error
});
You could use the next function but you should have setup an error handler and you need to pass the error (Docs):
app.get('/project', (req, res, next) => {
con.query("SELECT * FROM issues", (err, result) => {
// don't throw, just respond appropriately
//if (err) throw err;
if (err)
next('error occured');
else
res.send(result);
});
});
// Error handler
app.use(function (err, req, res, next) {
console.error(err)
res.status(500).send('error occured')
});
I am trying to authenticate a user with custom callback in passport js. I have written my code based on the passport documentation.
router.post("/signin/email", function (req, res, next) {
passport.authenticate("email-local", function (err, user, info) {
if (err) {
return res.send("err");
}
if (!user) {
return res.send(info);
}
req.logIn(user, function (err) {
if (err) {
return res.send(err);
}
next(user);
});
})(req, res, next),
UsersController.getToken;
});
I want to pass the user to the next middleware i.e UsersController.getToken ,but it is not being passed. How can i solve this issue?
Passport will add the user data to req.user after login is called so you don't need to pass it with next.
I would recommend simplifying the req.logIn call to the following:
return req.logIn(user, next)
Then within you UsersController.getToken middleware you can access the user data through the req object.
After people log into my Express app, I'd like to redirect them to a url that reads:
www.mysite.com/:user
What I'm having trouble with is that my req.params object is coming up as an empty object literal when people get re-directed after logging in.
Ideally what I'd like to do is to somehow take the information stored in req.user and pass some of that information into the URL.
So basically I'd like to get from here:
router.post('/login',
passport.authenticate('local', {successRedirect:'/', failureRedirect: '/login', failureFlash: true}));
To here:
router.get('/:user', function(req, res) {
//stuff
}
After logging in the req.user object reads like this:
{
username: joesmith#mail.com,
name: Joe Smith,
password: dkei348#$kDL^583L,
formulas: []
}
And the code I'm attempting to use is as follows:
router.get('/:user', function(req, res) {
var user = req.user.name;
req.params = {
"user": user
}
But this doesn't work because initially req.user.name is undefined if someone isn't already logged in, so I can't get past the console error.
Apparently I don't understand how req.params is generated in enough detail to get around this problem.
Thank you.
If you want to have username in parameters you shoud redirect to '/' + req.user.name); because '/' doesn't have any params. That's why it is undefined. (additionaly you shoud check if parameter is defined and handle the error, so instead of console error you get error 404 or get to next, proper routing path).
Passport Documentation privides examples of doiung it:
app.post('/login',
passport.authenticate('local'),
function(req, res) {
// If this function gets called, authentication was successful.
// `req.user` contains the authenticated user.
res.redirect('/' + req.username);
});
or more complex custom callback :
app.get('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/' + user.name);
});
})(req, res, next);
});
But I think it is not a good practice and safer would be to redirect to the proper page/content by req.user value without putting it to URL, for example setting req.auth. and then using next(); instead of res.redirect('/' + user.name); to get to the next middleware. There username would be taken from req.auth.username, not from /:username.
How does the structure of your routing looks? You shoud make sure router.get('/:user' .. is not before router.get('/login'...
Looks like you are wanting to access whatever /:user value is. e.g. www.mysite.com/stretch0. Therefore you would access it like var user = req.params.user;
You can provide a custom handler, instead of letting Passport do all the redirecting:
app.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) {
req.flash('error', 'Unable to authenticate user');
return res.redirect('/login');
}
if (! user) {
return res.redirect('/login');
}
req.logIn(user, function(err) {
if (err) {
req.flash('error', 'Unable to log in user');
return res.redirect('/login');
}
return res.redirect('/' + user.username);
});
})(req, res, next);
});
This does mean that each logged-in user gets their "personal" URL, because you're redirecting to /USERNAME. I'm not sure from your question if that's actually your intention.
I would like some help understanding the following example from the passport.js authenticate documentation:
app.get('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/users/' + user.username);
});
})(req, res, next); //***UNSURE ABOUT THIS***
});
I understand what the code does - but I don't know what the (req, res, next)at the end of the callback function is for. Why is it necessary? Does it provide the values for (err, user, info)? If that's the case, why don't I see more function calls ending with arguments - Is it perhaps something to do with passing on the next object?
Would love for someone to help me improve my understanding of this concept.
Request handlers are Express middleware; they get a request, a response, and a way to pass on execution to the next layer of middleware. passport.authenticate returns middleware, but it hasn’t been attached with app.use(), so you have to pass the appropriate arguments manually.
The fact that the callback from passport.authenticate also has three arguments is just a coincidence. They won’t have the same values.