Passport.js optional authentication
authentication, javascript, node.js, oauth-2.0, passport.js
Solution
Here's a simple PoC:
var express = require('express');
var app = express();
var server = app.listen(3012);
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
app.use(passport.initialize());
passport.use(new LocalStrategy(function(username, password, done) {
if (username === 'foo' && password === 'bar') {
return done(null, { username : 'foo' });
}
return done(null, false);
}));
app.get('/api', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
var data = { hello : 'world' };
// Only if the user authenticated properly do we include secret data.
if (user) {
data.secret = '3133753CR37';
}
return res.send(data);
})(req, res, next);
});
It's calling `passport.authenticate` 'manually' in the `/api` endpoint. That way, you get more control over how to deal with authentication error (which—in your situation—shouldn't be treated as errors but as a way of limiting the output).
Here's the output without proper authentication:
$ curl 'localhost:3012/api?username=foo&password=wrong'
{"hello":"world"}
And here's with:
$ curl 'localhost:3012/api?username=foo&password=bar'
{"hello":"world","secret":"3133753CR37"}
To use as a middleware:
var middleware = function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
req.authenticated = !! user;
next();
})(req, res, next);
};
app.get('/api', middleware, function(req, res, next) {
var data = { hello : 'world' };
if (req.authenticated) {
data.secret = '3133753CR37';
}
return res.send(data);
});
Problem
Is there an optional authentication middleware from Passport.js? Let's say I have a route, `/api/users`. I want to give just a list of users to the public, but to authenticated people, I want to add more fields. Currently I have just a dumb custom method that does the same thing, but I wonder if: - Passport.js already provides such thing or - how can I make this a part of passport, like a plugin or so. My method, roughly, looks like ``` function optionalAuth(req, res, next) { var authHeader = req.headers.authorization; var token = parseToken(authHeader); // just getting the OAuth token here if(!token) { return next(); } User.findOne({ token: token }, function(err, user) { if(err) { return res.json(401, {message: 'auth expired'}); }; if(user) { req.user = user; } next(); }); } ``` This, however, seems dumb to me, and also not in passport-auth-strategies.js or some other auth layer where I think it should be. What is the better way to do it? Bonus points for telling me if I'm doing the proper thing returning 401 if I find a token but it's invalid :)