user5392394
user5392394

Reputation:

Node.js - How do I set up separate authentication for different routes?

I'm working on Node.js a project that's using basic-auth for password protection. Currently, the auth.js file provides the same username/password for all routes. How would I adjust this to use a different username/password for each route?

auth.js file:

const auth = require('basic-auth');
const username = 'admin';
const password = 'supersecret';
const internalIp = 'xxx.xx.xxx.xxx';

module.exports = function(app) {

  app.use((req, res, next) => {
    const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;

    // whitelist internal IP
    if (ip === internalIp) {
      next();
    } else {

      const user = auth(req);

      if (user === undefined || user.name !== username || user.pass !== password) {
        // Return 401 error if user/pass is incorrect or empty
        res.statusCode = 401;
        res.setHeader('WWW-Authenticate', 'Basic realm="Research tool"');
        res.end('Unauthorized');
      } else {
        next();
      }
     }
  });
};

app.js file:

var express = require('express');
var app = express();
var auth = require('./sources/auth.js');

// Run auth around app first
auth(app);

app.get('/route1', function(req, res) {
  res.render('pages/route1');
}

app.get('/route2', function(req, res) {
  res.render('pages/route2');
}

app.listen(port, function() {
  console.log('App listening on port: ' + port);
});

Running: node v6.11.1, express 4.13.4, basic-auth 1.1.0

Upvotes: 2

Views: 2227

Answers (2)

Zac Delventhal
Zac Delventhal

Reputation: 4010

It's very unusual that you have usernames and passwords hard-coded in. What is more typical, is that usernames and (hashed) passwords are stored in a database. Then when an authorization request comes in, you use the username to fetch the password and just compare the two passwords to each other. In this way, one piece of auth middleware could service any number of username/password combinations.

That said, if you really need two separate pieces of auth middleware, the better way is to insert the needed middleware into each route. Something like this:

auth.js

const auth = require('basic-auth')

const getAuthorizer = (name, pass) => (req, res, next) => {
  const user = auth(req)
  if (!user || user.name !== name || user.pass !== pass) {
    res.status(401).send('Unauthorized')
  } else {
    next()
  }
}

const admin = getAuthorizer('admin', 'supersecret')
const user = getAuthorizer('user', '12345')

module.exports = { admin, user }

app.js

const express = require('express')
const app = express()
const auth = require('./sources/auth')

app.get('/route1', auth.admin, (req, res) => {
  res.render('pages/route1')
})

app.get('/route2', auth.user, (req, res) => {
  res.render('pages/route2')
})

app.listen(port, () => {
  console.log('App listening on port: ' + port)
})

Upvotes: 1

Bartosz Herba
Bartosz Herba

Reputation: 343

You can get url from request object in app.js so you could include route => credentials map either from file or internal code. Then you will be able to iterate over map to check if route matches passed credential data.

Upvotes: 0

Related Questions