Requiring extended permissions with the JS SDK without necessarily using FB.login()

dshap picture dshap · Sep 13, 2011 · Viewed 9.4k times · Source

I'm working on a canvas app and I want to accomplish the following with the JS SDK:

  • Check if the user has granted specific extended permissions

    • If so, call some function startServerProcess()

    • If not, display the auth dialog to get permissions and alert the user if they don't provide sufficient access.

I want to completely handle this on the client-side such that startServerProcess() is never called unless the user provides the right permissions, given that the server script it executes relies on these permissions.

After searching I found this solution, but it solely uses FB.login() which I don't want to call every time, because if the user is already authenticated, an annoying auth dialog opens and then automatically closes immediately after.

My initial solution is to call FB.getLoginStatus() and then make a graph api call to /me/permissions if possible and only call FB.login() if I actually have to show an auth dialog.

Here's the code I have as of now:

$('#my_ui_button').click(function() {
    require_perms(function(is_authenticated) {
        if(!is_authenticated) {
            startServerProcess();
        } else {
            alert('Sorry, we cannot start the server process until you grant permission');
        }
    });
});


function require_perms(callback) {
    // check if the user is logged in + connected to the app
    FB.getLoginStatus(function(response) {

        // if the user is logged in, continue to check permissions
        if(response.authResponse) {
            FB.api('/me/permissions', function(perms_response) {

                // if photo access already exists, we're good to go
                if(perms_response['data'][0]['user_photos'] && perms_response['data'][0]['friends_photos']) {
                    console.log('permissions are already granted.');
                    callback(true);

                    // photo access does not exist, so show an auth dialog
                } else {

                    // get photo permissions
                    console.log('requesting permission...');
                    FB.login(function(response) {
                        if(response.authResponse) {
                            console.log('permission granted');
                            callback(true);
                        } else {
                            console.log('permission request failed');
                            callback(false);
                        }
                    }, {
                        scope : 'user_photos,friends_photos'
                    });
                }
            });
            // user is not connected to the app, so show an auth dialog
        } else {

            // get photo permissions
            console.log('requesting permission...');
            FB.login(function(response) {
                if(response.authResponse) {
                    console.log('permission granted');
                    callback(true);
                } else {
                    console.log('permission request failed');
                    callback(false);
                }
            }, {
                scope : 'user_photos,friends_photos'
            });
        }
    });
}

Does this seem like a messy way of solving the problem? I particularly don't like the fact that I'm repeating that FB.login() code but I ran into some issues eliminating that given the asynchronous nature of the graph api call (or maybe I just need some more sleep).

Any comments/advice would be greatly appreciated. Thanks.

Answer

Abby picture Abby · Sep 13, 2011

I think this is significantly over-complicating what could just be achieved with FB.login(). FB.login() will only cause the pop up if the user is not logged in (so they will need it anyway) or if the session cookie isn't available. You could just call FB.getLoginStatus() after initialising the page which will make sure the cookie is added immediately if available.

The pop up is pretty much unavoidable, and is standard behaviour on most apps. I don't think your solution would gain much over simply:

FB.init({...});
FB.getLoginStatus();

then

FB.login({},{scope:...});