Node-restify: Simple authentication example?

Created on 11 Mar 2012  路  11Comments  路  Source: restify/node-restify

Hello, could you provide a simple authentication example?

For instance I have set the server like this:

// Create server instance
var server = module.exports = restify.createServer({
    name : 'test-api'
  , version : '0.0.1-dev'
});

// Middlewares
server.use(restify.acceptParser(server.acceptable));
server.use(restify.authorizationParser());
server.use(restify.dateParser());
server.use(restify.queryParser({ mapParams : false }));
server.use(restify.urlEncodedBodyParser());
server.use(restify.bodyParser({ mapParams : false }));
server.use(restify.throttle({
    burst : 100
  , rate : 50
  , ip : true
  , overrides : {

    }
}));

and client like this:

var client = restify.createJsonClient({
    url: 'http://localhost:3003'
  , versions : '0.0.1-dev'
});
client.basicAuth('panosru', '123123');

Then on server I can get my username with req.username, and I can see that in req.authorization I have those info:

authorization: 
   { scheme: 'Basic',
     credentials: 'cGFub3NydToxMjMxMjM=',
     basic: { username: 'panosru', password: '123123' } }

but how I should apply the authentication mechanism?

Thanks in advance! :)

Most helpful comment

Hi,

Well, you'd have to add your own plugin that checks parameters, like:

server.use(function authenticate(req, res, next) {
    myPretendDatabaseClient.lookup(req.username, function (err, user) {
        if (err) return next(err);

        if (user.password !== req.authorization.basic.password)
            return next(new restify.NotAuthorizedError());

        return next();
    });
});

Assuming you have some kind of way of looking up a user/password pair. Obviously that's trivial example (as you'd probably be salting passwords, etc.), but hopefully that gives you the gist.

m

All 11 comments

Hi,

Well, you'd have to add your own plugin that checks parameters, like:

server.use(function authenticate(req, res, next) {
    myPretendDatabaseClient.lookup(req.username, function (err, user) {
        if (err) return next(err);

        if (user.password !== req.authorization.basic.password)
            return next(new restify.NotAuthorizedError());

        return next();
    });
});

Assuming you have some kind of way of looking up a user/password pair. Obviously that's trivial example (as you'd probably be salting passwords, etc.), but hopefully that gives you the gist.

m

@mcavage hello, sorry for getting back so late, thanks for the example :)

Hi @panosru @mcavage how would this work ? Wouldn't req be inaccessible?
I think we need another event which would trigger right after a request is made (node's native request does not work).

How would you get the plug in to work with req (request)?

@mcavage Any way you could get into more detail on how to use Restify in this way? I am having uber-trouble understanding how to use Restify + Passport to create a (moderately) secure RESTful auth system. I cannot figure out how to check authentication again after the initial callback from Passport

I have written a quick guide about using authorizationParser as part of Stack Overflow answer. Might be useful, http://stackoverflow.com/a/27442155/368691.

Can anyone show me example how to use passport with restify? I don't have any error but I don't see cookie is set by passport.

I wanted to make a "basic auth" middleware to password-protect some static content. The above documentation got me part way there, but it didn't work from a browser, which needs a certain header to request authentication from a user. Since restify errors do not respect headers set with res.header() I had to manually send the 401 error, and importantly I had to call next() with a value of false.

Here's the working middleware I came up with:

var basicAuth = function(req, res, next){                                       
  res.header('WWW-Authenticate','Basic realm="API Docs"');            

  if (                                                                          
    !req.authorization ||                                                       
    !req.authorization.basic ||                                                 
    !req.authorization.basic.password                                           
  ){                                                                            
    res.send(401);                                                              
    return next(false);                                                         
  }                                                                             

  checkUserPassword(req.authorization.basic.password, function(err,data){        
    if (err || !data){                                                          
      res.send(401);                                                            
      return next(false);                                                       
    }                                                                           
    else return next();                                                         
  });                                                                           
};

Then, to use this middleware, it can be inserted on a specific route:

server.get('/docs/', basicAuth, routes.displayDocumentation);

Or it can be "used" ahead of all routes that need basic authentication:

server.use(basicAuth);

Your milage may vary, but hopefully this is helpful to someone. The simplified middleware code doesn't provide the checkUserPassword() function, doesn't check the username at all, and isn't concerned with specific error-handling. Adjust to taste.

Thank you for the example @tapmodo. The need for next(false) makes sense, as that is used as a signal to the server that the response is done being processed.

Can you clarify what you mean by:

restify errors do not respect headers

Were you not able to send the WWW-Authenticate header to the client as part of the 401 response? If so, then we should look into that to make sure that it is sent. Could you also try: res.setHeader and see if that has a similar result?

To clarify, it appears that this code:

res.header('WWW-Authenticate','Basic realm="API Docs"');
return next(new restify.NotAuthorizedError());

...does not pass the header.

That's not a big problem (and may be desirable), but I did need to work around it.

It's definitely a surprise when it isn't sent. I'm wondering if using res.setHeader directly will behave any differently.

Just added this: https://github.com/restify/node-restify/issues/1099. Thought it could help someone. Cheers.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

stevehipwell picture stevehipwell  路  8Comments

augustovictor picture augustovictor  路  4Comments

sloncho picture sloncho  路  3Comments

sonnyp picture sonnyp  路  7Comments

0v3rst33r picture 0v3rst33r  路  6Comments