1
votes

I'm trying to login to my meteor site via a third party library like this one: https://gist.github.com/gabrielhpugliese/4188927

In my server.js i have:

Meteor.methods({
facebook_login: function (fbUser, accessToken) {
    var options, serviceData, userId;
    serviceData = {
        id: fbUser.id,
        accessToken: accessToken,
        email: fbUser.email
    };
    options = {
        profile: {
            name: fbUser.name
        }
    };
    userId = Accounts.updateOrCreateUserFromExternalService('facebook', serviceData, options);
    return userId;
}, ......

In my client.js I have:

    facebookLogin: function () {
    if (Meteor.user())
        return;
    if (!Session.equals("deviceready", true))
        return;
    if (!Session.equals("meteorLoggingIn", false))
        return;

    // Do not run if plugin not available
    if (typeof window.plugins === 'undefined')
        return;
    if (typeof window.plugins.facebookConnect === 'undefined')
        return;
    // After device ready, create a local alias
    var facebookConnect = window.plugins.facebookConnect;
    console.log('Begin activity');
    Session.equals("meteorLoggingIn", true);
    Accounts._setLoggingIn(true);
    facebookConnect.login({
        permissions: ["email", "user_about_me"],
        appId: "123456789012345"
    }, function (result) {
        console.log("FacebookConnect.login:" + JSON.stringify(result));

        // Check for cancellation/error
        if (result.cancelled || result.error) {
            console.log("FacebookConnect.login:failedWithError:" + result.message);
            Accounts._setLoggingIn(false);
            Session.equals("meteorLoggingIn", false);
            return;
        }

        var access_token = result.accessToken;

        Meteor.call('facebook_login', result, access_token, function (error, user) {
            Accounts._setLoggingIn(false);
            Session.equals("meteorLoggingIn", false);
            if (!error) {
                var id = Accounts._makeClientLoggedIn(user.id, user.token);
                console.log("FacebookConnect.login: Account activated " + JSON.stringify(Meteor.user()));
            } else {
                // Accounts._makeClientLoggedOut();
            }
        }); 
    });
}, // login
facebookLogout: function () {
    Meteor.logout();
    // var facebookConnect = window.plugins.facebookConnect;
    // facebookConnect.logout();
},

The third party library (Facebook Android SDK in my case) works fine. My problem is after the "var id = Accounts._makeClientLoggedIn(user.id, user.token);" the Meteor.user() returns Undefined. However If I do a page refresh in the browser works fine and the template renders as a logged in user.

Anyone knows how to fix the 'Undefined' on client ??

PS. On server side the users collection looks fine. The meteor token and everything else are there.

2

2 Answers

1
votes

Solved. I had to add : this.setUserId(userId.id); after userId = Accounts.updateOrCreateUserFromExternalService('facebook', serviceData, options); at server.js

0
votes

Meteor's client side javascript can't run fibers. Fibers allows synchronous code to be used with javascript since by design js is asynchronous. This means there are callbacks that need to be used to let you know when the task is complete.

From what it looks like Accounts._makeClientLoggedIn doesn't take a callback & unfortunately and doesn't return any data looking at its source. I can't say i've tried this myself because I can't test your code without the android sdk but have you tried using Deps.flush to do a reactive flush?

Also Meteor also has very clean and easy facbeook integration. If you simply add the facebook meteor package

meteor add accounts-facebook

You can get access to a lovely Meteor.loginWithFacebook method that can make everything reactive and your code simpler and really easy. If you need to modify it to use the Android SDK Dialog instead you can easily modify the code out as the code for the module is out there for you to hack up to your spec

Edit: If you're using an external SDK such as the java SDK/cordova plugin

Set your plugin so that it redirects to the following URL (set up for meteor.com hosting):

http://yourmeteorapp.meteor.com/_oauth/facebook?display=touch&scope=your_scope_request_params&state=state&code=yourOAuthCodeFromJava&redirect=YourAPP

So in the querystring we have:

  • scope= Contains your facebook scope params (for permissions)
  • code= Your OAuth code from the java sdk
  • redirect=Where to redirect to after once logged in instead of the window.close
  • state= A cros site forgery state value, any random value will do

This url is basically used to mimic would what be given to the REDIRECT_URI at : https://developers.facebook.com/docs/reference/dialogs/oauth/

This will redirect to meteor's OAuth helper (at https://github.com/meteor/meteor/blob/master/packages/accounts-oauth-helper/oauth_server.js)

So what would happen is you give the OAuth code from Java to meteor, it fetches the OAuth token and the user's data, then redirect the user to a URL in your app