Facebook Android SDK reauthorizeForPublish() loses old permissions

In Requesting extended permissions, I explained how to request extended permissions with the Facebook Android SDK. If you use this method to request different kinds of permissions at different stages, you would notice that making a call to [cci]session.reauthorizeForPublish()[/cci] with new permissions clears the already existing permissions from the session object and thus the call [cci]session.getPermissions()[/cci] would later return just the new permissions that are recently granted. This means that the Session object’s notion of its permissions is out of sync with the Facebook service and the access token associated with the Session still has those permissions and can still be used to make Graph API calls requiring any of the permissions it has been granted earlier (unless the user has subsequently revoked any of them, of course). This is a bug with the Facebook SDK.

An approach to work around this problem is to store the permissions that have been granted to us by persisting it in the Android Application class. The application class is the base class to maintain global application state. If you don’t already have an application class for your application, you can create one by extending Application.

public class MyApplication extends Application {

	Set<String> permissions;

	public Set<String> getPermissions(Collection<String> sessionPermissions) {
		if (permissions == null)
			permissions = new HashSet<String>();

		permissions.addAll(sessionPermissions);
		return permissions;
	}

	public void setPermissions(Set<String> permissions) {
		this.permissions = permissions;
	}

	public void addPermissions(Collection<String> newPermissions) {
		if (this.permissions == null) {
			this.permissions = new HashSet<String>();
		}
		this.permissions.addAll(newPermissions);
	}

	public void clearPermissions() {
		if (this.permissions != null)
			this.permissions.clear();
	}

}

Register the class in AndroidMaifest.

<application
 android:icon="@drawable/icon"
 android:label="@string/app_name"
 android:name="MyApplication">

The first thing we need to do now is to obtain the current permissions granted by the user for our session when the app is launched (and user is already loggeed in) or when the user logs in using Facebook. I use the following method to retrieve current permissions from Facebook and persist them in the application object. This should be called in onSessionStateChanged when a new session is opened or in onCreate if the user is already logged in.

protected void retreiveCurrentPermissions(Session session) {
	FacebookClient fbClient = new DefaultFacebookClient(session.getAccessToken());
	JsonObject resultJson = fbClient.fetchObject("me/permissions", JsonObject.class);
	List<String> permissions = new ArrayList<String>();
	try {
		if (resultJson.getJsonArray("data").length() > 0) {
			JsonObject permissionsJson = resultJson.getJsonArray("data").getJsonObject(0);
			for (String key : JsonObject.getNames(permissionsJson)) {
				if (permissionsJson.getInt(key) == 1) {
					permissions.add(key);
				}
			}
		}
		((MyApplication) getApplication()).addPermissions(permissions);
	} catch (JsonException e) {
		e.printStackTrace();
	}
}

Another important point to keep in mind is to clear the permissions if the user logs out of Facebook. This can be done by calling ((MyApplication) getApplication()).clearPermissions(); in onSessionStateChanged when the session is closed.

Now we are persisting the session permissions in our application object. Before performing an operation that requires extended permission, we should now check if the required permissions are already present in ((MyApplication)getApplication()).getPermissions(session.getPermissions()); and make a Reauthorization request if this is not the case. In this case, we will then have to add the permissions in onSessionStateChanged if the state of the session is SessionState.OPENED_TOKEN_UPDATED.

Published 14 Jan 2013

I build mobile and web applications. Full Stack, Rails, React, Typescript, Kotlin, Swift
Pulkit Goyal on Twitter