Get Facebook app_scoped_user_id From Facebook ID

Those of you who use the Facebook Graph API know that there were some big changes with the release of version 2.0. One of the biggest? Instead of returning a user's Facebook ID, the API is now returning an app_scoped_user_id, a unique identifier to each app/user combo.

If you were using the old Facebook ID, this change can cause big problems. Facebook says, "No matter what version they originally used to sign up for your app, the ID will remain the same for people who have already logged into your app. This change is backwards-compatible for anyone who has logged into your app at any point in the past." But, if you ever change the information you're requesting, Facebook will force users to re-authorize and you'll get the new app-scoped user ID, even for legacy users of your app.

Take me, for example. I never used to collect email addresses from Facebook on my running log; instead, I just used the Facebook ID to recognize the user. But, I also have other sites, such as my personal website that were using the Facebook sign in too, so now the API was returning two different IDs and I couldn't match up a future user across sites. Not good. To solve this, I decided to start collecting the email from Facebook, but doing so caused users to have to re-authenticate and suddenly I had two different Facebook IDs for each user and no way of tying them together. This led me to the big question…

How do you get a user's Facebook app_scoped_user_id from their Facebook ID?

Eventually, I came up with a solution, but it took a while. So, I'm hoping to save you that same hassle by posting the steps here.

Step 1: Create a business within Facebook. Even if you're not a business or are a business with only one site or app, start here. This documentation explains all the actions you'll need to take.

Step 2: Use the ids_for_business API endpoint to get data. The Facebook Graph API's ids_for_business endpoint will return a list of all app_scoped_user_id's for a user if you give it the user's original Facebook ID. Here's some example code:

@session_start();

$app_id = your_facebook_app_id;
$app_secret = 'your_facebook_app_secret';
$my_url = 'http://www.example.com/update-facebook-ids.php';
$debug = true;

if (empty($_REQUEST['code'])) {
	$_SESSION['state'] = md5(uniqid(rand(), TRUE)); //CSRF protection
	$dialog_url = 'https://www.facebook.com/dialog/oauth?client_id='.$app_id.'&redirect_uri='.urlencode($my_url).'&state='.$_SESSION['state'];
	echo '<script>top.location.href=\''.$dialog_url.'\';</script>';
	custom_die('Your browser isn\'t allowing you to be redirected to Facebook\'s log in page. Please lower your security settings to Medium High and then try again.');
} elseif (!is_string($_REQUEST['code'])) {
	custom_die('Code must be a string.'); //helps prevent malicious activity
}

//this link is helpful during testing because simply hitting refresh in your browser won't work (because <em>code</em> is already the query string)
echo '<p><a href="'.$my_url.'">Try Again</a></p>';

if ($_REQUEST['state'] == $_SESSION['state']) {
	$token_url = 'https://graph.facebook.com/v2.1/oauth/access_token?client_id='.$app_id.'&redirect_uri='.urlencode($my_url).'&client_secret='.$app_secret.'&code='.strip_tags($_REQUEST['code']);
	$response = file_get_contents($token_url);
	$params = null;
	parse_str($response, $params);
	
	//$users is an example array of user data. replace as appropriate
	foreach ($users as $user) {
		$graph_url = 'https://graph.facebook.com/v2.1/ids_for_business?id='.$user['facebook_id'].'&access_token='.$params['access_token'];
		if ($debug) { echo '<p>Connecting to: '.$graph_url.'&hellip;</p>'; }
		$data = json_decode(file_get_contents($graph_url));
		if ($debug) { echo '<p>Response, stored in $data:</p><pre>'.print_r($data,true).'</pre>'; }
		//here's where you should save your new app_scoped_user_id for each user
	}
} else {
	custom_die('The state does not match. You may be a victim of CSRF.');
}

Step 3: Save the app_scoped_user_id. After you get the new app-scoped ID, you can save it and then use it to recognize the user in the future.

That's all of the steps. Not too bad, right? I guess not. But… Now that I've done the work, allow me to rant a little about this new policy.

Why is Facebook not returning user IDs any more? Privacy is the claimed reason – they say this is to "better protect people's info" – but how is somebody's user ID personal info that needs to be protected? If anything, this is going to result in less privacy because it will cause sites (like mine) to start collecting email and using that as an identifier since the Facebook ID is no longer available.

Further, even if there is a valid reason for protecting the user's Facebook ID, this new change doesn't actually protect it. A call to the Graph API user endpoint returns a "link" field containing a URL that can be used to access the user's Facebook profile. A simple cURL request to that URL will return the ID to you, no problem. In fact, I took a look at the source of my own Facebook profile page (after accessing it from that URL) and found my Facebook ID listed 227 times. That's some protected info there, huh?


Comments

Loading…

This post was published on September 5th, 2014 by Robert James Reese in the following categories: Facebook and PHP. Before using any of the code or other content in this post, you must read and agree to our terms of use.