Correct Authentication Pattern using Passport.js - node.js

It seems the Passport docs suggest using a pattern such as:
app.get("/my/protected/resource", passport.authenticate("local"), function(req, res){
res.json({my:"protected resource"});
});
as the standard way to protect resources after authentication. However, as I have tried this strategy repeatedly, it has repeatedly given me 401 - Unauthorized. Rather, a middleware solution such as the following worked:
exports.loggedIn = function(req, res, next) {
console.log('Checking credentials...');
if(req.isAuthenticated()){
next();
} else {
res.redirect("/");
}
};
This, however, is either not found, or is not made prominent in the docs. Which of these two are the standard and correct way of protecting resources using passport.js?

If you are using sessions, I generally use this type of pattern:
app.get('/resource', passport.authenticate('local', {
successRedirect: '/success',
failureRedirect: '/login',
failureFlash: 'Invalid username or password'
}))
as shown http://passportjs.org/guide/authenticate/
If you want the response in the same function:
app.get('/resource', passport.authenticate('local', {
failureRedirect: '/login',
failureFlash: 'Invalid username or password'
}), function(req, res){
res.json({my:"protected resource"});
})

If you want to be redirected to "/" (as your second example does) rather than getting a 401 (the default behavior) when trying to access a protected resource unauthenticated, using passport.authenticate, you can use the redirect options, as specified in the second section of the page in the docs that you linked:
app.get("/my/protected/resource",
passport.authenticate("local", {failureRedirect: '/' }),
function(req, res){
res.json({my:"protected resource"});
});

Related

Intercepting flash message

I am using Passport authentication with 'local' strategy for my application. I want the user to be able to know if the username and password entered by user is invalid and if valid then redirect to dashboard.
This is how i am authenticating the user:
router.post('/login', passport.authenticate('local', {failureRedirect: '/login', failureFlash: 'Invalid username or password.'}), function(req, res, next){
res.redirect('/users/dashboard');
});
Redirect part works fine, but the user enters invalid user/pass the flash message in failureFlash: 'Invalid username or password.' dosent show up on the login page.
This is how i handle my login route:
router.get('/login', function(req, res, next) {
res.render('pages/login', {'title' : 'VoteCenter - Login', message: req.flash('message')});
});
What do i need to use in req.flash('??????') to intercept the flash mesaage coming from failureFlash?
You can get message through req.flash('error')(default)
also you can pass failureFlash object with your custom message name like it:
failureFlash: { type: 'authError', message: 'Invalid username or password.'}
then get message req.flash('authError')

node.js+passport local authentication

I am developing a web app where after login according to type of user the page should redirect. type of user is defined by user at the time of sign-up. passport local authentication is working fine but what I have to do for redirecting the page according to usertype.. please guide
If the passport is working you could probably get that information off of the request and then use res.redirect('/whereYouWant'). Post some code? check out this answer for info on looking at the cookie: How to access Cookie set with Passport.js
Why not redirect to a page which takes of any redirections for you? Example:
router.get('/login', function(req, res) {
res.render('login', { user : req.user, status: req.param('status') });
});
router.post('/login', passport.authenticate('local', {
successRedirect: '/redirect',
failureRedirect: '/login?status=fail',
}));
router.get('/redirect', function(req, res) {
if (req.isAuthenticated()) {
if (req.user.usertype === "admin") {
res.redirect('/adminpage');
}
if (req.user.usertype === "marketing") {
res.redirect('/marketingpage');
}
......
}
});

More Passport.js woes - hangs on form submission

I am setting up what I thought would be the simplest auth possibly - a site loads on a log in screen, user enters credentials in a form, on submission I am using Passport.JS and Sequelize to check the credentials. Most all of this is copied from various tutorials, or the Passport website itself.
No matter what I do, change or attempt though, the site just hangs as soon as I click the form submit button. In the dev tools network tab I just shows the post request to /login as pending.
To eliminate all possible added problems, I stripped out Sequelize, and used hard coded users, ala the local use example on the passport github page. Still, no change, to Sequelize was not the problem.
I'm sure it's something dumb. I've tried the obvious solutions, like making sure my form was sending 'username' and 'password'.
My form looks like this:
form(method="post", action="/login")
fieldset
legend Please Log In
label(for="username") Username:
input#username(type='text', name="username", autocomplete="off")
label(for="password") Password:
input#password(type='password', name="password")
button#login(type="submit") Log In
In node my app.js uses a router, which includes this:
var login = require('../app/controllers/login');
app.get('/', login.index);
app.post('/login', login.auth);
The page load ok on the get request. On post it directs to this:
exports.auth = function (req, res, next) {
console.log(req.body);
passport.authenticate('local', {
successRedirect: '/home',
failureRedirect: '/',
failureFlash: true
});
};
The console.log(req.body) comes up fine, showing the form values, so we are ok to that point. But nothing after. This is the last part:
passport.use(new LocalStrategy(
function(username, password, done) {
console.log('local strat invoked');
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 swapped out the code that used Sequelize to check the DB for the user with this findByUsername function (copied and pasted straight from the above mentioned post on the passport github page), but as the console.log('local strat invoked') is never coming up, I'm guessing nothing after that point even matters.
Also includes are the passport.serializeUser and passport.deserializeUser, but I cant imagine those are the problem at the stage where I am stuck.
Any idea what step I am missing to get this working?
Passport is middleware, if you embed it in a route handler function, you need to invoke it:
exports.auth = function (req, res, next) {
console.log(req.body);
passport.authenticate('local', {
successRedirect: '/home',
failureRedirect: '/',
failureFlash: true
})(req, res, next); // <-- NEED TO INVOKE WITH req, res, next
};
or, more simply use it as middleware (which is the recommended approach:
exports.auth = passport.authenticate('local', {
successRedirect: '/home',
failureRedirect: '/',
failureFlash: true
});

nodejs + passport + express 3.0 + connect-flash no flashing?

I'm using a passport-local strategy for authenticate users. I followed the guide given by Jared Hanson and installed connect-flash in order to give flash method to the req object. So one of my request handlers is the following:
app.post('/login',
passport.authenticate('local', {
successRedirect: '/'
, failureRedirect: '/login'
, successFlash: 'Bienvenido'
, failureFlash: 'Credenciales no vĂ¡lidas'
})
);
When the user login fails, it redirects the user to /login again but it doesnt flash anything :/
UPDATE:
I use mongodb for session storage and I see this:
> db.sessions.find()
{ "_id" : "qZ2eiTnx6r9LR25JOz/TGhiJ", "session" : "{\"cookie\":{\"originalMaxAge\":null,\"expires\":null,\"httpOnly\":true,\"path\":\"/\"},\"passport\":{\"user\":\"4ffb5b5db9cc16b615000001\"},\"flash\":{\"error\":[\"Credenciales no vĂ¡lidas\"],\"success\":[\"Bienvenido\"]}}" }
So the messages are inserted into the session object but they aren't pulled out. Should I do something special?
I assume you're pulling the messages out and rendering them in a view? Something like:
app.get('/login', function(req, res){
res.render('login', { message: req.flash('error') });
});

Custom returnUrl on Node.js Passport's Google strategy

I'm using Express and Passport OpenID Google strategy and I would like to set returnURL on each auth request to be able to return to the page that initiated that auth.
The situation is that I have HTML5 slides application with Node.js backend (and with social stuff and editor and Portal and extensions... https://github.com/bubersson/humla) and I want be able to log in user on some slide (via slide menu...) but then I want him to get back to same slide easily.
So I would need something like this?
app.get('/auth/google', function(req,res) {
var cust = "http://localhost:1338/"+req.params.xxx;
passport.authenticate('google', returnURL:cust, function ...
}
I've read Passport's guide, but still don't know how to do that. I know this wouldn't be safe, but how else could I do it?
Or how can I make the application to return to the page from where the login has been initiated? Or is there a way to make OpenID authentication using AJAX (and still be able to use passport as well)?
I've figured this out for my apps Twitter authentication, I am sure that the GoogleStrategy is quite similar. Try a variant of this:
Assuming you have defined the route for the callback from the authentication service like so (from the passport guide):
app.get('/auth/twitter/callback',
passport.authenticate('twitter', {
successRedirect: authenticationRedirect(req, '/account')
, failureRedirect: '/'
})
);
Just change that block to this:
app.get('/auth/twitter/callback', function(req, res, next){
passport.authenticate('twitter', function(err, user, info){
// This is the default destination upon successful login.
var redirectUrl = '/account';
if (err) { return next(err); }
if (!user) { return res.redirect('/'); }
// If we have previously stored a redirectUrl, use that,
// otherwise, use the default.
if (req.session.redirectUrl) {
redirectUrl = req.session.redirectUrl;
req.session.redirectUrl = null;
}
req.logIn(user, function(err){
if (err) { return next(err); }
});
res.redirect(redirectUrl);
})(req, res, next);
});
Now, define your middleware for authenticated routes to store the original URL in the session like this:
ensureAuthenticated = function (req, res, next) {
if (req.isAuthenticated()) { return next(); }
// If the user is not authenticated, then we will start the authentication
// process. Before we do, let's store this originally requested URL in the
// session so we know where to return the user later.
req.session.redirectUrl = req.url;
// Resume normal authentication...
logger.info('User is not authenticated.');
req.flash("warn", "You must be logged-in to do that.");
res.redirect('/');
}
Works!
Wherever you have your login button, append the request's current URL as a
query parameter (adjust for whatever templating system you use):
<a href='/auth/google?redirect=<%= req.url %>'>Log In</a>
Then, add middleware to your GET /auth/google handler that stores this value in
req.session:
app.get('/auth/google', function(req, res, next) {
req.session.redirect = req.query.redirect;
next();
}, passport.authenticate('google'));
Finally, in your callback handler, redirect to the URL stored in the session:
app.get('/auth/google/callback', passport.authenticate('google',
failureRedirect: '/'
), function (req, res) {
res.redirect(req.session.redirect || '/');
delete req.session.redirect;
});
Try res.redirect('back'); in the callback for passport.authenticate
According to the author this isn't possible with OpenID strategies. We managed to update these dynamically by directly accessing the variables:
app.get('/auth/google', function(req, res, next) {
passport._strategies['google']._relyingParty.returnUrl = 'http://localhost:3000/test';
passport._strategies['google']._relyingParty.realm = 'http://localhost:3000';
passport.authenticate('google')(req, res, next);
});

Resources