Android FacebookSDK login with native Facebook app installed asks for permissions even after the user have already given them

Claudio Freitas picture Claudio Freitas · Jun 7, 2013 · Viewed 9.3k times · Source

Condition: Android device with native Facebook apk installed but logged out.

Every time this condition is met and the user tries to login using either Facebook's LoginButton or doing it manually (see below), after logged in, the Facebook SDK always asks for permission to access the user data, even if the user has already given permission.

Here is the code I'm implementing on my application:

Version 1 - Login Button:

XML:

<com.facebook.widget.LoginButton
    android:id="@+id/login_button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

Java:

private static final List<String> PERMISSIONS = Arrays.asList("email", "user_groups");
private UiLifecycleHelper uiHelper;

@Override
protected void onCreate(Bundle savedInstanceState){
    uiHelper = new UiLifecycleHelper(this, callback);
    uiHelper.onCreate(savedInstanceState);
    loginButton = (LoginButton) findViewById(R.id.login_button);
    loginButton.setReadPermissions(PERMISSIONS);
}

private Session.StatusCallback callback = new Session.StatusCallback() {
    @Override
    public void call(Session session, SessionState state, Exception exception) {
        //modify interface or something
    }
};

Version 2 - Manually

XML:

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/button"
    android:onClick="buttonOnClick"
    android:text="Login" />

Java:

private static final List<String> PERMISSIONS = Arrays.asList("email", "user_groups");

public void buttonOnClick(View v) {
    System.out.println("botaoOnClick");
    Session session = Session.getActiveSession();
    if (!session.isOpened() && !session.isClosed()) {
        System.out.println("session: " + session);
        session.openForRead(new Session.OpenRequest(this).setPermissions(PERMISSIONS).setCallback(callback));
    }
    else {
        Session.openActiveSession(this, true, callback);
    }
}

private Session.StatusCallback callback = new Session.StatusCallback() {
    @Override
    public void call(Session session, SessionState state, Exception exception) {
        //modify interface or something
    }
};

Even the sample apps that come with sdk works this way, but I have already seen some other apps (eg. Foursquare) working the way I think is the natural behavior (only asks for permissions if the user hasn't already given them).

So, does anyone know a way to achieve the desired result? Preferably without editing the Facebook SDK itself.

Thanks in advance!

Edit 1: Additional information: upon checking the session variable on the callback method, the permissions always come empty when the condition above is met. If the user refuses to give permission (not for the first time), and tries to login again, the session comes with the permissions the user already gave some time in the past, as expected.

Edit 2 (on 2013-06-28): I've decided to upload a video reproducing the issue, since I am not so sure everyone understood what I've meant in my explanation.

Link here: http://www.youtube.com/watch?v=w4qJfoiVSsU

Answer

Gomino picture Gomino · Jun 24, 2013

Thats probably because you got a signature mismatch between your app (which I assume is in debug mode) and your facebook app associated to your appID.

Basically you should make sure that:

  1. The signature of your android app that use the facebook sdk is added to the facebook app dashboard Facebook App Dashboard you can easily get your app signature by using keytool or by adding this code in your activity's onCreate method :

    @Override
    protected void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    
    try {
        PackageInfo info = getPackageManager().getPackageInfo(
                getPackageName(), 
                PackageManager.GET_SIGNATURES);
        for (Signature signature : info.signatures) {
            MessageDigest md = MessageDigest.getInstance("SHA");
            md.update(signature.toByteArray());
            Log.d("TAG", "Hash to copy ==> "+ Base64.encodeToString(md.digest(), Base64.DEFAULT));
            }
    } catch (NameNotFoundException e) {
    
    } 
    catch (NoSuchAlgorithmException e) {
    
    }
    }
    
  2. Facebook Login checkbox is Enabled

  3. If your not enabling sandbox mode you need to choose a category from the app detail page

  4. By default the loginbutton use the SingleSignOn loginbehavior, which will basically log you in as the owner of the facebook app, I suggest you to use the one that allow any user to log on in behalf of your facebook app. To do so, just add this line after you set the permission to the login button:

    loginButton.setReadPermissions(PERMISSIONS);
    loginButton.setLoginBehavior(SessionLoginBehavior.SUPPRESS_SSO);
    

If you still having troubles, I suggest you to read this doc troubleshooting facebook login

PS: And FYI, If you use UiLifecycleHelper, don't forget to override the main activity/fragment lifecycle methods, and forward the calls to the UiLifecycleHelper as stated in the javadoc.

When using this class, clients MUST call all the public methods from the * respective methods in either an Activity or Fragment. Failure to call all the * methods can result in improperly initialized or uninitialized Sessions.

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override
protected void onResume() {
    super.onResume();
    uiHelper.onResume();
}

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    uiHelper.onSaveInstanceState(outState);
}

@Override
protected void onPause() {
    super.onPause();
    uiHelper.onPause();
}

@Override
protected void onDestroy() {
    super.onDestroy();
    uiHelper.onDestroy();
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    uiHelper.onActivityResult(requestCode, resultCode, data);
}