iosfacebooknode.jsmeteormeteorite

How can I login to Meteor with native device Facebook?


Suppose I logged into my device's Facebook authentication, like system Facebook on iOS. I obtain an access token.

How can I use the access token to login to Meteor's Facebook Oauth provider?


Solution

  • To login with Facebook using an access token obtained by another means, like iOS Facebook SDK, define a method on the server that calls the appropriate Accounts method:

    $FB = function () {
        if (Meteor.isClient) {
            throw new Meteor.Error(500, "Cannot run on client.");
        }
    
        var args = Array.prototype.slice.call(arguments);
        if (args.length === 0) {
            return;
        }
        var path = args[0];
        var i = 1;
        // Concatenate strings together in args
        while (_.isString(args[i])) {
            path = path + "/" + args[i];
            i++;
        }
    
        if (_.isUndefined(path)) {
            throw new Meteor.Error(500, 'No Facebook API path provided.');
        }
        var FB = Meteor.npmRequire('fb');
    
        var fbResponse = Meteor.sync(function (done) {
            FB.napi.apply(FB, [path].concat(args.splice(i)).concat([done]));
        });
    
        if (fbResponse.error !== null) {
            console.error(fbResponse.error.stack);
            throw new Meteor.Error(500, "Facebook API error.", {error: fbResponse.error, request: args});
        }
    
        return fbResponse.result;
    };
    
    Meteor.methods({
        /**
         * Login to Meteor with a Facebook access token
         * @param accessToken Your Facebook access token
         * @returns {*}
         */
        facebookLoginWithAccessToken: function (accessToken) {
            check(accessToken, String);
    
            var serviceData = {
                accessToken: accessToken
            };
    
            // Confirm that your accessToken is you
            try {
                var tokenInfo = $FB('debug_token', {
                    input_token: accessToken,
                    access_token: Meteor.settings.facebook.appId + '|' + Meteor.settings.facebook.secret
                });
            } catch (e) {
                throw new Meteor.Error(500, 'Facebook login failed. An API error occurred.');
            }
    
            if (!tokenInfo.data.is_valid) {
                throw new Meteor.Error(503, 'This access token is not valid.');
            }
    
            if (tokenInfo.data.app_id !== Meteor.settings.facebook.appId) {
                throw new Meteor.Error(503, 'This token is not for this app.');
            }
    
            // Force the user id to be the access token's user id
            serviceData.id = tokenInfo.data.user_id;
    
            // Returns a token you can use to login
            var loginResult = Accounts.updateOrCreateUserFromExternalService('facebook', serviceData, {});
    
            // Login the user
            this.setUserId(loginResult.userId);
    
            // Return the token and the user id
            return loginResult;
        }
    }
    

    This code depends on the meteorhacks:npm package. You should call meteor add meteorhacks:npm and have a package.json file with the Facebook node API: { "fb": "0.7.0" }.

    If you use demeteorizer to deploy your app, you will have to edit the output package.json and set the scrumptious dependency from "0.0.1" to "0.0.0".

    On the client, call the method with the appropriate parameters, and you're logged in!

    In Meteor 0.8+, the result of Accounts.updateOrCreateUserFromExternalService has changed to an object containing {userId: ...} and furthermore, no longer has the stamped token.