Search code examples
node.jsmongodbexpressmongoosebasic-authentication

BasicAuth with Express and Mongoose


I'm trying to add a basic authentication to my Express paths. To check if the combination user/pass is correct, I read the collections usermodels in my MongoDB database. Here is my code :

server.js

var normal = express.basicAuth(normalAuth);

app.get('path', normal, function(req, res){etc.});

function normalAuth(user, pass) {
  var mongo = require('./database/userManager');
  var result = false;
  mongo.start(mongo.list(function(err, data) {
      if(err) { throw err; }
      else {
        console.log('Getting list from db...');
        for(var i in data) {
          console.log('Getting details from db...');
          if(user == data[i].name && pass == data[i].pass) {
            console.log('New connection : ' + user);
            result = true;
            break;
          }
          else {
            console.log('Failed connection : ' + user);
            result = false;
          }
        }
        console.log('OK');
      }
      mongo.mongoose.connection.close();
  }));
  return result;
}

userManager.js

var mongoose = require('mongoose');

var userModel = mongoose.connection.model('usermodel', new mongoose.Schema({
    name: String,
    pass: String,
    status: { type: Boolean, default: false }
}), 'usermodels');

function start(callback) {
  mongoose.connect('mongodb://localhost/derp', function(err) {
      if(err) { throw err; }
      else { 
        console.log('Connected to database ');
      }
  });
}

function list(callback) {
  userModel.find(callback); 
}

The authentication almost works, it connects to the db and get the informations. It prints on the console

"New connection : /*user connected*/". 

But there is a problem : my function normalAuth always return false, so even if I have correct user/pass, I can't access the pages and I have the connection window as if I gave wrong user/pass. I guess it is because this function return the result before my mongo.start(blabla) finished, but I don't know what to do.

Thank you for your help.


Solution

  • You always get false result because in Node.js every IO operation is asynchronous.

    Let me explain: When you call mongo.start(...) function, Node.js will put that in another operation queue because it is IO operation. Main operation queue must not be blocked, and that is why IO operations are always asynchronous. Ater mongo function is put in another queue of operations, your main operation queue will continue and get to the line of code: return false. And it will return false regardless what function mongo.start(...) will do with it.

    Solution is by sending callback function:

    function normalAuth(user, pass, callbackResult) {
      var mongo = require('./database/userManager');      
      mongo.start(mongo.list(function(err, data) {
          if(err) { throw err; }
          else {
            console.log('Getting list from db...');
            for(var i in data) {
              console.log('Getting details from db...');
              if(user == data[i].name && pass == data[i].pass) {
                console.log('New connection : ' + user);
                // here you send true to callback function
                callbackResult(true);
                break;
              }
              else {
                console.log('Failed connection : ' + user);
                // here you send false to callback function
                callbackResult(false);
              }
            }
            console.log('OK');
          }
          mongo.mongoose.connection.close();
      }));
    }
    

    And you call this function like this:

    normalAuth(user, pass, function(result) {
        if(result)
            console.log("Auth OK");
        else
            console.log("Auth Failed");
    }
    

    EDIT: In express.basicAuth function it will be called like this:

    app.use(express.basicAuth(function(user, pass, callback) {
        normalAuth(user, pass, function(result) {     
            callback(null /* error */, result);
        }
    }));