Nyxynyx
Nyxynyx

Reputation: 63647

How to Avoid Repeating Passport.JS Code Used in Multiple Express.JS Routes

I just started using Passport.js in my Express app for creating a API with authenticated routes.

Question: If I have 2 routes defined in routes/animals.js and routes/locations.js which uses Passport to protect certain API requests, where I need to create a passport object and run passport.use(new BearerStrategy...) before i can use passport.authenticate later in the code.

How can I avoid repeating the passport.use(new BearerStrategy...) code in all the routes file? Or is it better to repeat them?

routes/animals.js

var passport = require("passport");
passport.use(new BearerStrategy(
function(token, done) {
    User.findOne({ token: token }, function (err, user) {
    if (err) { return done(err); }
    if (!user) { return done(null, false); }
    return done(null, user, { scope: 'all' });
    });
}
));

router.get('/', 
    passport.authenticate('bearer', { session: false }),
    function(req, res, next) {
        Animal.find(function(err, animals) {
            if (err) return next(err);
            res.json(animals)
        })
})

app.js

var animalsRouter = require('./routes/animals');

app.use('/api/animals', animalsRouter);

...

Upvotes: 1

Views: 447

Answers (1)

Cisco
Cisco

Reputation: 22952

Node.js modules are Singleton-like. Meaning whenever you do require('passportjs'), you are getting back the same instance you imported in another file.

For your case, in every route file, you are importing the same Passport instance every time. So you only need to define your Passport configuration once.

So for example, define you BearerStrategy in another file:

bearer-strategy.js

module.exports = new BearerStrategy((token, done) => {
  // ...
});

Then in your main app.js, configure Passport only once:

app.js

const express = require('express');
const passport = require('passport');
const bearerStrategy = require('./bearer-strategy.js');

const app = express();

// Only need to do this once
passport.use(bearerStrategy);

But now you need to protect your API routes and avoid repeating yourself. You can do this, by applying the Passport middleware to /api/** instead of /api/myRouter for every router. So your animals router can be:

routes/animals.js

const express = require('express');
const router = express.Router();

router.get('/', (req, res) => res.json(req.user));

module.exports = router;

Now we need an API router which just mounts all the other routers:

routes/api.js

const express = require('express');
const router = express.Router();

const animalRouter = require('./animals.js');

router.use('/animals', animalRouter);
// other routers

module.exports = router;

Now finally, we can mount them in one shot and secure them with Passport once:

app.js

const express = require('express');
const passport = require('passport');
const bearerStrategy = require('./bearer-strategy.js');
const apiRouter = require('./routes/api.js')

const app = express();

passport.use(bearerStrategy);

app.use('/api', passport.authenticate('bearer', { session: false }), apiRouter);

As an aside, all plugins/whatever for Express are just middleware.

Upvotes: 1

Related Questions