javascriptnode.jsmeteormeteor-restivus

How to consume a REST api that needs username/password authentication in node.js


I want to consume a REST api that needs a username/password authentication in node.js. The code that consumes the api is as follows:

var request = require('request');

var url = 'http://localhost:3000/api/v1/login/'

request.get(url,{'auth': {'user': 'test35','pass': 'mypassword','sendImmediately': false}},function(err, httpResponse, body) {
  if (err) {
    return console.error('post failed:', err);
  }

  console.log('Post successful!  Server responded with:', body);
});

With the above code, the error I get is:

{
  "status": "error",
  "message": "API endpoint does not exist"
}

The api is written in meteor restivus and you can see it in the following question's answer here

In the API, when I remove the api's authRequired: true, i.e, remove

{
        routeOptions: {
            authRequired: true
        }
  }

and in the code that consumes the API above, change url from

'http://localhost:3000/api/v1/login/

to:

http://localhost:3000/api/v1/articles/

and run "node accessRESTapi.js", I am able to consume the REST api! What I am not able to do correctly is the authentication when "authRequired: true" is set as per above! Please help


Solution

  • EDIT: Updated based on info from comments

    The style of request is quite different between logging in to get a token and the subsequent requests:

    For login

    The docs specify that login actions must be done with a POST request to /api/login/ with a body that contains username or email and password as url-encoded params

    var request = require('request');
    
    var url = 'http://localhost:3000/api/v1/login/'
    var user = 'test35';
    var pass = 'mypassword';
    
    // Save these for future requests
    var userId;
    var authToken;
    
    // Use POST instead of GET
    request.post(
      {
        uri: url,
        // I'm using form because it matches the urlEncoding behaviour expected by `restivus`
        form: { username: user, password: pass }
      },
      function(err, httpResponse, body) {
        if (err) {
          return console.error('post failed:', err);
        }
        var json = JSON.parse(body);
        authToken = json.data.authToken;
        userId = json.data.userId;
        console.log('Post successful!  Server responded with:', body);
      }
    );
    

    For future requests

    Now you need to set the correct headers with the previously saved userId and authToken

    According to the docs, that means X-User-Id and X-Auth-Token headers on all subsequent requests

    var request = require('request');
    
    var url = 'http://localhost:3000/api/v1/articles/'
    
    request.get({
      uri: url, 
      headers: {
        'X-User-Id': userId,
        'X-Auth-Token': authToken
      }
    }, function(err, httpResponse, body) {
      if (err) {
        return console.error('get failed:', err);
      }
    
      console.log('Get successful!  Server responded with:', body);
    });
    

    Putting it together:

    We want to make sure we get the authToken before making any further requests.

    This means making the second request in the callback of the first function like so:

    var request = require('request');
    
    var url = 'http://localhost:3000/api/v1/login/';
    var user = 'test35';
    var pass = 'mypassword';
    
    // Save these for future requests
    var userId;
    var authToken;
    
    // Use POST instead of GET
    request.post(
      {
        uri: url,
        // I'm using form because it matches the urlEncoding behaviour expected by `restivus`
        form: { username: user, password: pass }
      },
      function(err, httpResponse, body) {
        if (err) {
          return console.error('post failed:', err);
        }
        var json = JSON.parse(body);
        authToken = json.data.authToken;
        userId = json.data.userId;
        console.log('Post successful!  Server responded with:', body);
    
        // And now we make the second request
        // Welcome to callback hell
        var articlesUrl = 'http://localhost:3000/api/v1/articles/';
    
        request.get({
          uri: articlesUrl, 
          headers: {
            'X-User-Id': userId,
            'X-Auth-Token': authToken
          }
        }, function(err, httpResponse, body) {
          if (err) {
            return console.error('post failed:', err);
          }
    
          console.log('Get successful!  Server responded with:', body);
        });
      }
    );