I saw the example code at http://passportjs.org/docs that we can pass third parameter for done function of passport
Code:
var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}
));
In this case they are passing { message: 'Incorrect username.' }.
My question is how to handle this third parameter.
EDIT:
This is my routing code:
app.post('/login',
passport.authenticate('local', { failureRedirect: '/login' }),
function(req, res) {
res.redirect('/');
});
I want to know how to use message that send from passport like
res.render('myjade', {'message': **THAT MESSAGE**})
something like this
From the docs:
Redirects are often combined with flash messages in order to display status information to the user.
Setting the failureFlash option to true instructs Passport to flash an error message using the message given by the strategy's verify callback, if any.
Note: Using flash messages requires a req.flash() function. Express 2.x provided this functionality, however it was removed from Express 3.x. Use of connect-flash middleware is recommended to provide this functionality when using Express 3.x.
So modify your call to authenticate to be:
passport.authenticate('local', {
failureRedirect: '/login',
failureFlash: true
}),
and then either use the connect-flash middleware or define your own middleware to provide the req.flash() function.
Related
I am new in the developing field. This is my first project and I desperately need help to resolve the issue about CORS.
In my project, I am going to put my website on another domain using an iframe tag. I have used Passport.js local strategy it is not working with CORS for Iframe on another domain.
Please help me how to resolve this issue even let me know should I use JWT or any other strategy.
Following is my passport code
const LocalStrategy = require('passport-local').Strategy;
const bcrypt = require('bcryptjs');
// Load User model
const User = require('../models/User');
module.exports = function(passport) {
passport.use(
new LocalStrategy({ usernameField: 'full_mobile' }, (full_mobile, password, done) => {
// Match user
User.findOne({
full_mobile: full_mobile
}).then(user => {
if (!user) {
return done(null, false, { message: 'That mobile is not registered' });
}
// Match password
bcrypt.compare(password, user.password, (err, isMatch) => {
if (err) throw err;
if (isMatch) {
return done(null, user);
} else {
return done(null, false, { message: 'Password incorrect' });
}
});
});
})
);
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
};
I am using cors middleware
app.use(cors({credentials: true, origin: true}));
Following is code for login
// Login
router.post('/login', (req, res, next) => {
passport.authenticate('local', {
successRedirect: '/dashboard',
failureRedirect: '/users/login',
failureFlash: true
})(req, res, next);
});
Thank you!
Perhaps it is related to the version of the node.js module passport you are using. Our login had an unknown problem with the latest version, 0.5.2, i.e. timed out. Need to check if the parameters updated. Instead the easiest was to return back to 0.4.1.
You can update the version to the one you want with > npm install password#0.4.1 for example.
I have solved the issue by using JWT token-based API and sending the cookie with
httpOnly: false,secure:true,sameSite: 'none'
res.cookie("token", token, {
httpOnly: false,secure:true,sameSite: 'none'
});
I am trying to send the info message that gets set in my verify callback:
Here is the example from passport docs:
var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function(err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}
));
However if I write my route as:
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('/users/' + req.user.username);
});
That function does not get called with the info message. At least not that I know of. I know passport shoves the user into the req, as I can access it from req.user. Is there a way to access the info message like this. Or do I need to specify a custom callback?
Which they outline as:
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);
});
The part that is confusing is that they outline using a 3rd parameter in the done callback (from verify) that is a message, yet you can only access that if you write a custom callback. Is that true.
The adopted convention in the Passport framework is that the optional info object will be available through req.authInfo.
This however depends on the used strategy which is responsible for passing it to the Passport framework. For instance, the passport-http strategy does not forward the info object to Passport while the passport-local does.
Here is how you can then access it in a controller protected by the local strategy :
app.post('/login',
passport.authenticate('local'),
function (req, res) {
if (req.authInfo) {
// req.authInfo.message will contain your actual message.
}
});
This is driving me crazy!
I'm using Express 4, passport and local-passport to authenticate login and signup.
I'm using this example:
https://github.com/tutsplus/passport-mongo
Problem:
When the signup form does not validate (say you forgot one of the fields) and we redirect to the failureRedirect (which is the same signup page), all the entered values are gone. Not a very good user experience that you have to fill out the entire form because you messed up a single field.
How do I pass the already entered data on the the form?
I got these two routes handing the GET and POST of the form:
app.get('/signup', function(req, res){
res.render('signup', {
message: req.flash('message'),
});
});
app.post('/signup', passport.authenticate('signup', {
successRedirect: '/signup-complete',
failureRedirect: '/signup', // need to pass the entered values (if any) back to the signup page
failureFlash : true
}));
I have a nagging suspicion that the values are already there - I just don't know how to grab them.
I'm using Swig for the views btw.
Did you add connect-flash middleware to your app?
var flash = require('connect-flash');
app.use(flash());
Update:
When you define your local strategy, you should return the flash messages in the third parameter of the done function. Example:
passport.use(new LocalStrategy(
function(username, password, done) {
findByUsername(username, function(err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false, { message: 'Unknown user ' + username }); }
if (user.password != password) { return done(null, false, { message: 'Invalid password' }); }
return done(null, user);
})
});
}
));
I'm using passport to do a local authentication. It's pretty simple right now, just a simple login form and login route. It works perfectly when running on my mac, but when I upload it to a rackspace server and try it, I get a timeout when trying to submit the form to /login.
Relevant code (let me know if i need to add more):
//Passport SETUP
passport.serializeUser(function (user, done) {
console.log("serialized");
done(null, user.username);
});
passport.deserializeUser(function (username, done) {
console.log("deserialized");
user = users.getUserByUsername(username);
done(null, user);
});
passport.use(new LocalStrategy(
function (username, password, done) {
users.loginUser(username, password, function(err, user) {
if (err) { return done(err); }
if (user) {
return done(null, user);
} else {
return done(null, false, { message: 'Incorrect Login.'});
}
});
}
));
//middleware
var loginRequired = function(req, res, next){
if (req.isAuthenticated()) { return next(); }
res.redirect('/');
};
//using passport
app.post('/login',
passport.authenticate('local', { successRedirect: '/game',
failureRedirect: '/',
failureFlash: true })
);
//page that i want to eventually get to
app.get('/game', loginRequired, function(req, res){
res.render('game', {title:"Game Page"});
});
note - the deserialize right now is just a cheater that returns the user object, eventually it'll be a callback and all that :).
:( after throwing in console.logs everywhere I found out that it was mysql. The user wasn't created on the server. Not sure why mysql-simple-pool didn't error out, but it didn't.
How can I combine passport-local to return a JWT token on successful authentication?
I want to use node-jwt-simple and looking at passport.js I am not sure how to go about.
var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function(err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}
));
Is it possible to return the token when calling done() ?
Something like this... (just pseudo code)
if(User.validCredentials(username, password)) {
var token = jwt.encode({username: username}, tokenSecret);
done(null, {token : token}); //is this possible?
}
If not, how can I return the token?
I figured it out!
First of all you need to implement the correct strategy. In my case LocalStrategy, and you need to provide your validation logic. For example sake let's use the one in passport-local.
var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function(err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}
));
the verify call back you provide function(username, password, done) will take care of finding your user and checking if the password matches (beyond the scope of the question and my answer)
passport.js expects several pieces for it to work, one is that you return the user in the strategy. I was trying to change that part of the code, and that was wrong. The callback expects false if the validation fails and an object (the validated user) if you are successful.
Now.... how to integrate JWT?
In your login route you will have to handle a successful auth or an unsuccessful one. And it is here that you need to add the JWT token creation. Like so:
(remember to disable the session, otherwise you will have to implement the serialize and deserialize functions. And you don't need those if you are not persisting the session, which you are not if you are using a token based auth)
From passport-local examples: (with the JWT token added)
// POST /login
// This is an alternative implementation that uses a custom callback to
// achieve the same functionality.
app.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err) }
if (!user) {
return res.json(401, { error: 'message' });
}
//user has authenticated correctly thus we create a JWT token
var token = jwt.encode({ username: 'somedata'}, tokenSecret);
res.json({ token : token });
})(req, res, next);
});
And that is it! Now when you call /login and POST username and password (which should always be over SSL) the first code snippet above will try to find a user based on the username you provided and then check that the password matches (Of course you will need to change that to suit your needs).
After that your login route will be called and there you can take care of returning an error or a valid token.
Hope this will help someone. And if I have made any mistakes or forgot something let me know.
This is a great solution, I just want to add this:
var expressJwt = require('express-jwt');
app.use('/api', expressJwt({secret: secret}));
I like to use "express-jwt" to validate the token.
btw: this article is great to learn how to handle the token in the client side, using Angular, in order to send it back with every request
https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/
Here's a boiler-plate I'm working on for specifically using api tokens only (no sessions...not that session are bad of course; just we're using token approach):
https://github.com/roblevintennis/passport-api-tokens