I found a similar question here on StackOverflow, but had some trouble getting the answer provided to work. I converted it to middleware to make it fit in more nicely:
var includeAuth = function(req, res, next){
var header = req.header('authorization', false);
if(header){
var token = header.split(/\s+/).pop() || '';
if(token.length > 0){
var auth = new Buffer(token, 'base64').toString(),
parts = auth.split(/:/);
req.auth = {user: parts[0], pass: parts[1]};
}else
req.auth = false;
}else
req.auth = false;
next();
}
app.configure(function(){
app.use(includeAuth);
});
...but req.header.authorization
was never set. I was stumped, until I came across this gist, which hinted at the fact that even if the client was sending authorization headers, I still had to request them. So I added this:
if(req.auth){
// Do things
}else{
res.setHeader('WWW-Authenticate', 'Basic realm="Secure Area"');
res.statusCode = 401;
res.end("NO_CREDENTIALS");
}
I then started seeing data in req.auth
, but the object had the properties "username" and "password" rather than "user" and "pass" as I had specified. After a little more poking around, I discovered that... those are put there by Express automatically! Or so it seems, anyway. I made a new application without any middleware or other frills, and got the same results, so long as I sent that WWW-Authenticate header. This rendered my includeAuth
middleware function useless. Armed with my new-found knowledge, I can now use the following to provide specific error messages to the client when they try to authenticate:
function verifyAuth(req, res, appName, callback){
if(req.auth){
db.apps.findOne({id: appName}, function(err, app){ // Call to MongoDB
if(!err && app){
if(app.user === req.auth.username && app.pass === req.auth.password)
callback(null, true);
else
callback("INVALID_CREDENTIALS", false);
}else
callback("NO_SUCH_APP", false);
});
}else{
res.setHeader('WWW-Authenticate', 'Basic realm="Secure Area"');
res.statusCode = 401;
res.end(JSON.stringify({success: false, error: "NO_CREDENTIALS"}));
callback(null, false);
}
}
app.post('/:app/find', function(req, res){
verifyAuth(req, res, req.params.app, function(err, allowed){
if(!err && allowed){
// Do some things
}else if(err)
res.send({success: false, error: err});
});
});
However, I'm going to give Robert the correct answer, since his solution not only works perfectly, but also uses less (and simpler) code to get there, and will lend itself better to someone else's project, should they stumble across this question.