michael
michael

Reputation: 4547

how does the meteor-accounts oauth workflow happen

I'm trying to use accounts-facebook with the Ionic CLI. I'm using a client side bundler script but I can't get the entire oauth workflow to complete.

I set up a standard account-facebook config from the meteor-angular-socially project and discovered that I'm getting stuck at the oauth redirect URI. The following method is never called in my client-side bundle

// in script: oauth/oauth_client.js
// Called by the popup when the OAuth flow is completed, right before
// the popup closes.
OAuth._handleCredentialSecret = function (credentialToken, secret) {
  check(credentialToken, String);
  check(secret, String);
  if (! _.has(credentialSecrets,credentialToken)) {
    credentialSecrets[credentialToken] = secret;
  } else {
    throw new Error("Duplicate credential token from OAuth login");
  }
}; 

I get the following redirect URL from oauth which should load this page

# http://localhost:3000/_oauth/facebook/?code=[...]&state=[...]
<!DOCTYPE html>
<html>
<body>
  <p id="completedText" style="display:none;">
    Login completed. <a href="#" id="loginCompleted">
      Click here</a> to close this window.
  </p>

  <div id="config" style="display:none;">{
    "setCredentialToken":false,
    "storagePrefix":"Meteor.oauth.credentialSecret-",
    "isCordova":false
  }</div>
  <script type="text/javascript" src="/_oauth/facebook/end_of_popup_response.js">
    # script included inline for ease of reading
    (function () {

      var config = JSON.parse(document.getElementById("config").innerHTML);

      if (config.setCredentialToken) {
        var credentialToken = config.credentialToken;
        var credentialSecret = config.credentialSecret;

        if (config.isCordova) {
          var credentialString = JSON.stringify({
            credentialToken: credentialToken,
            credentialSecret: credentialSecret
          });

          window.location.hash = credentialString;
        }

        if (window.opener && window.opener.Package &&
              window.opener.Package.oauth) {
          window.opener.Package.oauth.OAuth._handleCredentialSecret(
            credentialToken, credentialSecret);
        } else {
          try {
            localStorage[config.storagePrefix + credentialToken] = credentialSecret;
          } catch (err) {
            // We can't do much else, but at least close the popup instead
            // of having it hang around on a blank page.
          }
        }
      }

      if (! config.isCordova) {
        document.getElementById("completedText").style.display = "block";
        document.getElementById("loginCompleted").onclick = function(){ window.close(); };
        window.close();
      }
    })();
  </script>
</body>
</html>

In the standard meteor CLI config, somehow/somwhere config.setCredentialToken === true and config.setCredentialToken and config.credentialSecret are set. But I cannot figure out where/when that happens.

In my accounts-facebook-client-side.bundle.js, none of this happens.

update

I realized that the magic happens on the Meteor server side. If I set my oauth redirect_uri to the port where the Meteor server is running, then I get the following in the ./_oauth/facebook page:

<div id="config" style="display:none;">{
"setCredentialToken":true,
"credentialToken":"bsgEZrFbK-UruR1iX81dEitIR0t5nC_a1HM4-EGSGx5",
"credentialSecret":"hi8rJxbyOsI0gVaoIHrr7N9kH9k2Fku1DYQXP5BmQMt",
"storagePrefix":"Meteor.oauth.credentialSecret-",
"isCordova":false
}</div>

BUT, I am guessing if I do that, I won't be able to read these values from localstorage(?) on my web.browser client page (port 3000)

any ideas for a workaround?

Upvotes: 0

Views: 362

Answers (1)

darkbasic
darkbasic

Reputation: 383

Simplest way to fix it is to put nginx in front of your app and use proxy_pass to sort calls towards Ionic's server and Meteor's server based on path:

server {
    listen       80;
    server_name  domain.tld;

    location / {
        proxy_pass http://domain.tld:8100;
    }
    location /_oauth {
        proxy_pass http://domain.tld:3000;
    }
    location /packages {
        proxy_pass http://domain.tld:3000;
    }
}

I just tried this method with accounts-facebook and works flawlessly (you will need to point your browser to http://domain.tld:80 instead of http://domain.tld:8100), but I already started digging deeper into Meteor's code to see if I can accomplish something better. I will edit this answer if I will find a better solution.

Upvotes: 0

Related Questions