Code Review Stack Exchange is a question and answer site for peer programmer code reviews. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have attempted to construct a simple RESTful node server that allows for user authentication using passport and jwt:

var express      = require('express');
var app          = express();
var bodyParser   = require('body-parser');
var morgan       = require('morgan');
var mongoose     = require('mongoose');
var passport       = require('passport');
var config       = require('./config/database'); // get db config file
var User         = require('./app/models/user'); // get the mongoose model
var port         = process.env.PORT || 8080;
var jwt          = require('jwt-simple');
var Cookies      = require('cookies');
var cookieParser = require('cookie-parser');

// get our request parameters
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(cookieParser());

// log to console
app.use(morgan('dev'));

// Use the passport package in our application
app.use(passport.initialize());

// Serve static 'todo' files
app.use(express.static('todo'));

// Serve Global Files
app.use('/assets', express.static('assets'));

app.use(function (req, res, next) {
  req.headers['authorization'] = 'JWT ' + req.cookies['access_token'] || 0;
  next();
});

// Frontpage Route (GET http://localhost:8080)
app.get('/', function(req, res) {
  res.sendfile('assets/front/templates/index.html');
});

app.get('/todo', passport.authenticate('jwt', { session: false}), function(req, res) {
  res.sendfile('assets/todo/templates/todo.html');
});

// connect to database
mongoose.connect(config.database);

// pass passport for configuration
require('./config/passport')(passport);

// bundle our routes
var apiRoutes = express.Router();

// create a new user account (POST http://localhost:8080/signup)
apiRoutes.post('/signup', function(req, res) {
  if (!req.body.name || !req.body.password) {
    res.json({success: false, msg: 'Please pass name and password.'});
  } else {
    var newUser = new User({
      name: req.body.name,
      email: req.body.email,
      password: req.body.password
    });
    // save the user
    newUser.save(function(err) {
      if (err) {
        return res.json({success: false, msg: 'Username already exists.'});
      }
      res.json({success: true, msg: 'Successfully created new user.'});
    });
  }
});

// route to authenticate a user (POST http://localhost:8080/authenticate)
apiRoutes.post('/authenticate', function(req, res) {
  User.findOne({
    name: req.body.name 
  }, function(err, user) {
    if (err) throw err;

    if (!user) {
      User.findOne({
        email: req.body.name 
      }, function(err, user) {
        if (err) throw err;

        if (!user) {
          //res.send({success: false, msg: 'Authentication failed. User not found.'});
          res.sendfile('assets/auth-fail/templates/auth-fail.html');
        } else {
          // check if password matches
          user.comparePassword(req.body.password, function (err, isMatch) {
            if (isMatch && !err) {
              // if user is found and password is right create a token
              var token = jwt.encode(user, config.secret);
              // return the information including token as JSON
              res.cookie('access_token', token);

              res.redirect('/memberinfo');
              //res.sendfile('assets/todo/templates/todo.html');
            } else {
              res.sendfile('assets/auth-fail/templates/auth-fail.html');
            }
          });
        }
      });
    } else {
      // check if password matches
      user.comparePassword(req.body.password, function (err, isMatch) {
        if (isMatch && !err) {
          // if user is found and password is right create a token
          var token = jwt.encode(user, config.secret);
          // return the information including token as JSON
          res.cookie('access_token', token);

          res.redirect('/memberinfo');

        } else {
          res.sendfile('assets/auth-fail/templates/auth-fail.html');
        }
      });
    }
  });

});

apiRoutes.get('/memberinfo', passport.authenticate('jwt', { session: false}), function(req, res) {
  var token = getToken(req.headers);
  if (token) {
    var decoded = jwt.decode(token, config.secret);
    User.findOne({
      name: decoded.name
    }, function(err, user) {
        if (err) throw err;

        if (!user) {
          return res.status(403).send({success: false, msg: 'Authentication failed. User not found.'});
        } else {
          res.json({success: true, msg: 'Welcome into the member area, ' + user.name + '!'});
        }
    });
  } else {
    return res.status(403).send({success: false, msg: 'No token provided.'});
  }
});

getToken = function (headers) {
  if (headers && headers.authorization) {
    var parted = headers.authorization.split(' ');
    if (parted.length === 2) {
      return parted[1];
    } else {
      return null;
    }
  } else {
    return null;
  }
};

apiRoutes.get('/logout', function(req, res) {
  res.cookie('access_token', '');
  req.headers['authorization'] = '';
  res.json({success: true, msg: 'See ya!'});
});

// connect the api routes under /api/*
app.use('/', apiRoutes);

// Start the server
app.listen(port);
console.log('Well...here we go again!: http://localhost:' + port);

Is there a better way to go about this? Specifically the '/authenticate' route, where i check for the username or the email address, and the '/logout' function. Open to hear of other improvements as well.

share|improve this question
    
I think a better way would be to user promises to unnest all those callbacks. – elclanrs 2 days ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.