Callback from 3rd party API Not getting current user

I’m connecting to a 3rd party API, Intuit Quickbooks, to get a user’s credentials. I’ve implemented the callback as they require and can successfully get the credentials. Within the callback, I call a meteor methods function to update the profile of the currently logged in user with the credentials passed in as a parameter. However, Meteor cannot find the user.

I’ve tried using Meteor.Async and BindEnvironment, but I get the same issue. Is it possible to know which user initiated the request to the 3rd party API when the API returns to the callback? I’m confused, please help.

var stuff;

Router.route('/requestToken', { name: 'requestoken', where: 'server' })
.get(function (req,res) {
  var QuickBooks = require('node-quickbooks');
  var request = require('request');
  var qs = require('querystring');
  var consumerKey    = 'xxxxx',
  consumerSecret = 'xxxxx'

  var postBody = {
    url: QuickBooks.REQUEST_TOKEN_URL,
    oauth: {
      callback:        'http://localhost:3000/callback/',
      consumer_key:    consumerKey,
      consumer_secret: consumerSecret
    }
  }
  console.log('abt to request')
  request.post(postBody, function (e, r, data) {
    var requestToken = qs.parse(data)
    stuff = requestToken.oauth_token_secret;
    console.log(requestToken)
    res.writeHead(301, {
      'Location': QuickBooks.APP_CENTER_URL + requestToken.oauth_token
    });
    res.end();
  })
})
.post(function () {
  // POST 
})
.put(function () {
  // PUT 
})



Router.route('/callback', { name:'callback' , where: 'server' })
.get(function () {
  var req = this.request;
  var res = this.response;

  var QuickBooks = require('node-quickbooks');
  var request = require('request');
  var qs = require('querystring');

  var consumerKey    = 'xxxxx',
  consumerSecret = 'xxxxx'

  var postBody = {
    url: QuickBooks.ACCESS_TOKEN_URL,
    oauth: {
      consumer_key:    consumerKey,
      consumer_secret: consumerSecret,
      token:           req.query.oauth_token,
      token_secret:    stuff,
      verifier:        req.query.oauth_verifier,
      realmId:         req.query.realmId
    }
  }

  request.post(postBody, Meteor.bindEnvironment(function (e, r, data) {
    var accessToken = qs.parse(data)
      qbo = new QuickBooks(consumerKey,
        consumerSecret,
        accessToken.oauth_token,
        accessToken.oauth_token_secret,
        postBody.oauth.realmId,
        true, // use the Sandbox
        true); // turn debugging on
      // test out account access
      qbo.findAccounts(function(_, accounts) {
        accounts.QueryResponse.Account.forEach(function(account) {
          console.log(account.Name)
        })
      });
      // save the access token somewhere on behalf of the logged in user
      var userCred = {
        token:accessToken.oauth_token,
        secret:accessToken.oauth_token_secret,
        real:postBody.oauth.realmId
      }
      console.log("about to call addQB details");
      console.log(userCred);
      //this method simply adds the userCred to the current logged in user's profile.
      //Whenever the method below is called from here, it never finds the user. However when called from the client it works well. 
      //Is it possibe to know logged user from a 3rd party API callback? / How can I go about this?
      Meteor.call("addUserQb",userCred); 
    }));

    res.end('<!DOCTYPE html><html lang="en"><head></head><body><script>window.opener.location.reload(); window.close();</script></body></html>')

  })
  .post(function () {
    // POST 
  })
  .put(function () {
    // PUT 
  })


And the method is as below. (The method works well when called from the client with a fake credentials obj as parameter. But won’t get user when called from callback in router above)

addUserQb:function(obj){
    Meteor.users.update(Meteor.userId(), {
      $set:{
        'profile.token': obj.token,
        'profile.secret': obj.secret,
        'profile.realmId' : obj.real
      }
    } );
}

I hope you’ve obfuscated your consumerKey and consumerSecret in the above code and that this is a server-only route.

Meanwhile I’ll keep looking through it :slight_smile:

Edit: If this is a server route (a REST endpoint) then there will be no logged-in user.

Thanks @robfallows, do you have any clues on how to save the data returned to the client who initiated the request? (And yes, this is a server route)

If this is from a Meteor client I would just use a standard Meteor.call to a server-side method.