Reputation: 719
I have the following code, and every time I type in 0.0.0.0:3000/user?apikey=xxx
, the code within local strategy never runs and it goes to "unauthorized" page directly. I tried to remove passport.authenticate from server.get('/user')
. In the debug mode, I could see that 'apikey' is parsed out to request parameter map. So the problem here is that passport is not able to authenticate get request. Any help will be greatly appreciated. Thanks!
var restify = require('restify');
// Create server
var server = restify.createServer({
name: 'server'
});
server.use(restify.queryParser());
server.use(restify.bodyParser());
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
function (apikey, done) {
console.log('Entered authentication.');
done(null, null);
}
));
//specify route
server.get('/user', passport.authenticate('local'), function (req, res) {
console.log(req.params);
res.end('haha');
});
server.listen(3000, function () {
console.log('%s listening at %s', server.name, server.url)
});
Upvotes: 2
Views: 3445
Reputation: 5454
An alternative approach is to simply use HTTP BASIC authentication. This way the userid/password is sent in the authorization header rather than part of the URI as this is a fairly common approach for securing services (just be sure you do this over HTTPS). I wrote this smallish module to do exactly that borrowed in part from some of the examples for passport-http.
var restify = require('restify'),
userId = process.env.serviceID,
pwd = process.env.servicePassword,
passport = require('passport'),
BasicStrategy = require('passport-http').BasicStrategy;
passport.use(new BasicStrategy(
function (username, password, done) {
findByUsername(username, function (err, user) {
if (err) {
return done(err);
}
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (user.password !== password) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}
));
var users = [
{ id: 1, username: userId, password: pwd}
];
function findByUsername(username, fn) {
for (var i = 0, len = users.length; i < len; i++) {
var user = users[i];
if (user.username === username) {
return fn(null, user);
}
}
return fn(null, null);
}
exports.authenticate = function (req, res, next, callback) {
passport.authenticate('basic', function (err, user) {
if (err) {
console.log(err);
return next(err);
}
if (!user) {
var error = new restify.InvalidCredentialsError("Failed to authenticate to ma-services.");
console.log(error);
res.send(error);
return next();
}
callback(req, res, next);
})(req, res, next);
};
To call it, I simply do the following from exported API calls that the server will call:
var basicAuth = require(__dirname + '/../utils/authn.js');
exports.count = function (req, res, next) {
basicAuth.authenticate(req, res, next, function() {
validateParam(req.params.uid, next);
var url = '/count/' + encodeURIComponent(req.params.uid);
processRequest(req, res, next, url);
});
};
Upvotes: 0
Reputation: 47993
The LocalStrategy is used for authenticating users via username and password. The passed function requires 3 arguments: username, password and a callback done. Your function only takes two apikey and done.
This strategy is not suitable for you as it authenticates the user via the credentials posted in the request, i.e. from a login page, which is helpful if you are using sessions. You on the other hand have to authenticate every GET request via apikey string in the url. So instead you should write a middleware for authenticating that.
server.use(function(req,res,next){
key=req.query['apikey']; //get key from url
//authenticate it
if(valid(key))
next();
else
res.redirect('/unauthorized');
});
Use this before your router.
Upvotes: 4