Understanding Passportjs Custom Callback - javascript

I'm experimenting with Passportjs and the code for a Custom Callback is:
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);
});
I'm happy with all of this code except for the second to last line (req, res, next); - Could someone explain why these parameters are added on the end. This is probably more of a JS question than a Passport question but any help is much appreciated.

The "javascript" answer is that it returns a function which is called again with those 2nd set of arguments.
That function is the "accumulator for failures from each strategy in the chain".
https://github.com/jaredhanson/passport/blob/master/lib/middleware/authenticate.js

You can rewrite it without the anonymous function, or the custom callback. Just use passport's passport.use(new LocalStrategy()) function to create the new strategy. See 'Configure' docs.
passport.use(new LocalStrategy(
function(username, password, done) {
logIn({ 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 only change you need to make is move the logIn function to be in this file, and not a method to req. Then you can simply call passport.authenticate like so:
app.get('/login', passport.authenticate('local', { successRedirect: '/',
failureRedirect: '/login' }));
So instead of using res.redirect in the callback, you just use passport's built in successRedirect and failureRedirect properties. You can see their docs as well, on the authentication page.

Connect/Express middleware function has signature:
function(req, res, next)
passport.authenticate() can be used as a middleware, e.g:
app.post('/login', passport.authenticate('local'), nextMiddleware);
This means authenticate() returns a middleware function object, which you can evoke with (req, res, next) parameters to continue the app's request-response cycle.

Related

Nodejs Passport Failure message not working

I have Passport Local working on my app.
Success brings authenticates and failure does not.
However im trying to make it fail better through fail messages and escaping the action.
Tried following the passport documentation.
The error messages are not appearing for some reason, would appreciate some assistance!
here is the local startegy
// Configure the local strategy for use by Passport.
passport.use(new Strategy(
function(username, password, cb) {
db.users.findByUsername(username, function(err, user) {
if (err) { return cb(err); }
if (!user) { return cb(null, false,req.flash('message','Invalid username or password')); }
if (user.password != password) { return cb(null, false,req.flash('message','Invalid username or password')); }
return cb(null, user);
});
}));
The authentication
//Home
app.post('/home.ejs',
passport.authenticate('local'),
function(req, res) {
res.redirect('/');
});
I also have another attempt at authentication if this is more accurate but also had no luck
//Home
app.post('/home.ejs', function( req, res, next) { passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); req.flash('message','Invalid username or password') }
if (!user) { return res.redirect('/'); failureFlash: 'Invalid username or password' }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/');
});
})(req, res, next);
});*/
It should be
passport.use(new LocalStrategy ...
instead of your
passport.use(new Strategy(.....

Passport Authenticate doesn't redirect

I was writing a local-signup strategy and noticed that it doesn't work so I stepped back and tried to authenticate against my empty collection. Every time I submit the form it takes ~30-40s until it results in a timeout. I ensured passport.authenticate() is called but it seems ike it's not doing any redirects and hence it is timing out because I am not rendering something either.
Questions:
I expected that it would do a redirect to the failureUrl (which is '/signup'), but instead nothing is happening. What am I doing wrong here?
Why there is no single log message coming from passport? This is driving me crazy because I have absolutely no idea what is going wrong there.
I am new to node.js and as far as I got I don't need to pass the configured passport object to the router but instead I can just do const passport = require('passport') is that correct?
This is my function handler for the /signup route:
function processSignup (req, res) {
logger.info("POST request received")
logger.info(req.body)
passport.authenticate('local', {
successRedirect : '/profile', // redirect to the secure profile section
failureRedirect : '/signup', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
})
}
Winston prints:
7:32:04 PM - info: POST request received 7:32:04 PM - info:
username=dassd#dass.de, password=dasdsa, submit=Register
My passport.js file looks like this:
const LocalStrategy = require('passport-local').Strategy
const User = require('./user-model')
const passport = require('passport')
// expose this function to our app using module.exports
function config() {
passport.serializeUser(function(user, done) {
done(null, user.id)
})
// used to deserialize the user
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user)
})
})
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);
});
}
));
}
module.exports = {
config: config
}
The relevant snipped of my app.js:
// required for passport
require('./authentication/passport').config();
app.use(cookieParser())
app.use(bodyParser())
app.use(session({
secret: 'secretToBeChanged',
saveUninitialized: false,
resave: false
}))
app.use(passport.initialize())
app.use(passport.session()) // persistent login sessions
app.use(flash()) // use connect-flash for flash messages stored in session
After a quick look at the documentation for passportjs, I think you need to do something like this:
function processSignup (req, res, next) {
logger.info("POST request received")
logger.info(req.body)
const handler = passport.authenticate('local', {
successRedirect : '/profile', // redirect to the secure profile section
failureRedirect : '/signup', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
});
handler(req, res, next);
}
passport.authenticate() returns a function that is meant to be used as the route handler function.
Normally, you would type something like:
app.post('/login', passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/login',
failureFlash: true
}));
But since you have abstracted with your own route handler function, you need to invoke the one returned from passport.authenticate().
In the end Mikael Lennholm was right and he pointed me into the right direction. I couldn't find that in any passport.js tutorials. However the passport.js documentation contains this code snippet which represents the same but I prefer it's code style:
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);

Persistent Login with Passport.js no longer working. isAuthenticated returns false

I had this code working at some point and must have lost it in a careless save at some point. I am trying to achieve persistent login with passport but it does not seem to be doing that as I am getting false on the isAuthentiacted middleware.
Here is my primary server.js setup, as you can see the order is good. But I am not sure about the cookie settings as I'm new to this whole thing.
app.use(cookieParser('S3CRE7'));
app.use(bodyParser.json());
app.use(session({ key: 'express.sid', resave: false, saveUninitialized: false, maxAge: 3000}));
app.use(passport.initialize());
app.use(passport.session());
app.use('/users/', usersRouter);
app.use('/transcriptions', transRouter);
app.use(express.static('public'));
const basicStrategy = new BasicStrategy(function(username, password, callback) {
let user;
User
.findOne({username: username})
.exec()
.then(_user => {
user = _user;
if (!user) {
return callback(null, false, {message: 'Incorrect username'});
}
return user.validatePassword(password);
})
.then(isValid => {
if (!isValid) {
return callback(null, false, {message: 'Incorrect password'});
}
else {
return callback(null, user)
}
});
});
passport.use(basicStrategy);
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
Here is my initial Log In endpoint with custom callback function, which logs in just fine, as well as stores a cookie on the client side
router.post('/login', function(req, res, next) {
passport.authenticate('basic', function (err, account) {
req.logIn(account, function() {
res.status(err ? 500 : 200).send(err ? err : account);
});
})(req, res, next)
});
isAuthenticated function:
const isAuthenticated = function (req, res, next) {
if (req.isAuthenticated())
return next();
console.log('not authenticated');
}
First lines of where the authentication fails:
router.get('/', isAuthenticated,
(req, res) => {
console.log(req);
});

Ui-router AngularJS: How to access to session variable 'req.user'

I'm using angular to deal with some routes,on the server side I'm using passport so basically I can acess to the user session variable req.user in my views , but when it comes to a route renderred by ui-router my req.user is undefined. Any idea to access to the req.user even it's not an express route
app.js code :
// Express Session
app.use(session({
secret: 'secret',
saveUninitialized: true,
resave: true
}));
// Passport init
app.use(passport.initialize());
app.use(passport.session());
// Global Vars
app.use(function (req, res, next) {
res.locals.success_msg = req.flash('success_msg');
res.locals.error_msg = req.flash('error_msg');
res.locals.error = req.flash('error');
res.locals.user = req.user || null;
next();
});
my passport code is as follows :
passport.use('employee',new LocalStrategy(
function(email, password, done) {
Employee.getUserByEmail(email, function(errEmp, emp){
if(errEmp ) throw errEmp;
if(!emp){
return done(null, false, {message: 'Unknown User'});
}
if(emp) {
Employee.comparePassword(password, emp.encryptedpass, function (err, isMatch) {
if (err) throw err;
if (isMatch) {
return done(null, emp);
} else {
return done(null, false, {message: 'Invalid password'});
}
});
}
});
}
));
router.get('/',ensureAuthenticated ,function(req, res, next) {
res.render('index', { title: 'Nubes' });
});
function ensureAuthenticated(req, res, next){
if(req.isAuthenticated()){
Employee.findById(req.user.id,function (err,emp) {
if(emp) {
res.render('employee/index');
}
})
}
}
router.post('/login', function(req, res, next) {
Employee.findOne({email:req.body.username},function (err,emp) {
if(emp){
passport.authenticate('employee', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/');
});
})(req, res, next);
})
});
In my rendered page 'employee/index' I can display my user information but routes that rendered by ui-router don't have a user variable
here is an example code of angular route :
$stateProvider
.state('home',{
url:'/',
templateUrl:'/views/employee/home.html'
})
in home.html user is not defined which is normal because it's not express server who rendred it . what I want is to get this user variable in my ui-router rendered pages
I suggest to implement token based authentication using something like JWT-tokens, you have also passport plugins for those.
If you still want to use sessions based info and pass it to the client, you can store them in some global JS variable, which i highly dont recommend.
here some info about jwt: https://scotch.io/tutorials/authenticate-a-node-js-api-with-json-web-tokens
for the locals if using handlebars it would look something like this:
<script>
var user = {{user}};
</script>
just note that you might need to implement some JSON stringify and decoding in order to get the info as JS object.

How can Passportjs return authenticate result instead of redirecting to another page

I am using passportjs for user authentication. In the official guide, the only shown user case is a redirection operation after authentication:
app.post('/login',
passport.authenticate('local', { successRedirect: '/',
failureRedirect: '/login',
failureFlash: true })
);
However, in my application, I don't want passport to redirect immediately. Instead, I hope passport could send me back some json object indicating whether the authentication is success or not. How I can do that?
You can send custom responses -
app.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) {
return next(err);
}
if (!user) {
return res.send(400, 'Incorrect username');
}
req.logIn(user, function(err) {
if (err) {
return next(err);
}
res.send({'message': 'User authenticated'});
});
})(req, res, next);
});

Categories

Resources