On a failed authentication at /login, passport.js saves an error message using failureFlash and redirects to /login (the same page). The sent HTML is correct (i.e., includes the failureFlash message), but is rendered incorrectly on the client side as 'undefined,' despite (in the Jade template) being in logic that guarantees it's defined. My route for the HTML (GET /login) and for the submission (POST /login) use the same URL; could that be part of the problem? The whole code-base can be found here.
app.js local strategy
passport.use(new LocalStrategy(
function(username, password, done) {
// asynchronous verification, for effect...
process.nextTick(function () {
var user = {'id': 1};
if(username !== "asdf") {
return done(null, false, { error: 'Unknown user '+username+'.'});
}else if(password !== "zxcv") {
return done(null, false, { error: 'Invalid password.'})
}
return done(null, user);
});
}
));
app.js login GET route
app.get('/login', function(req, res) {
var m1 = req.flash('error')[0]
console.log(m1)
res.render('login', { user: req.user, message: String(m1), sample: "Sanity check."});
});
app.js login POST route
app.post('/login',
passport.authenticate('local', { failureRedirect: '/login', failureFlash: 'THIS IS A SANITY CHECK ERROR', successFlash: 'Welcome!' }),
function(req, res) {
console.log('User login successful.');
var redirect_to = req.session.redirect_to || '/'
delete req.session.redirect_to;
res.send({redirect: String(redirect_to)})
//res.redirect(200, redirect_to);
});
app.get('/logout', function(req, res){
req.logout();
res.redirect(200, '/');
});
client_login.js served with /login's HTML
$(document).on('pageinit', function() {
$(document).on('click', '#submit', function() {
if($('#username').val().length > 0 && $('#password').val().length > 0){
// Send data to server through the ajax call
// action is functionality we want to call and outputJSON is our data
$.ajax({
url: '/login',
data: {action : 'login', username : $('#username').val(), password : $('#password').val()},
type: 'post',
async: 'true',
dataType: 'json'
})
.done(function (result) {
console.log('Done!');
window.location.replace(result.redirect);
})
.always(function (result) {
console.log('Always!');
})
.fail(function (request,error) {
console.log('Fail!');
// This callback function will trigger on unsuccessful action
//alert('Network error has occurred please try again!');
})
} else {
if($('#username').val().length <= 0 && $('#password').val().length > 0) {
alert('Please fill in your username.');
} else if($('#username').val().length > 0 && $('#password').val().length <= 0) {
alert('Please fill in your password.');
} else {
alert('Please fill in your username and password.');
}
}
return false; // cancel original event to prevent form submitting
})
})
login.jade
extends layout
block content
h1= title
if locals.expose.exists['client_login.js']
script(src='/dist/javascripts/client_login.js')
else
script(src='/javascripts/client_login.js')
div(style='max-width: 300px; margin:0 auto')
p(style='text-align: left') Please login to continue.
- if(typeof message !== 'undefined' && message.length > 0)
p Error! #{message}
p= sample
form(role='form', action='/login', method='post')
.form-group
input.form-control(type='text', data-clear-btn="true", name="username", id="username", value="", placeholder='Username')
.form-group
input.form-control(type='password', data-clear-btn="true", name="password", id="password", value="", placeholder='Password')
.form-group
button(type='submit', name='submit', id='submit' class="ui-btn ui-corner-all") Submit
HTML as sent from the server at bottom, rendered page at top. Note "undefined" vs "THIS IS A SANITY CHECK ERROR". Also note this project uses jQuery Mobile. Any ideas on what might be causing this behavior? The page's javascript shouldn't touch it, but there's also no visible flickering on redirect, which is good, but makes me suspicious.
Well, I'm dense. You can't redirect in response to an AJAX post.
So, I modified the AJAX post as below:
.fail(function (request,error) {
console.log('Fail!');
window.location.replace(window.location.href);
})
The window.location.replace(window.location.href);
feels a little clumsy & there is probably a better way to approach a page refresh, but for the moment, this works.
... This is why I post here. Rubber ducky debugging works.