How to handle access tokens with Facebook SDK v4.0

Access token handling best practices in Facebook PHP SDK v4.0

Jul 22, 2014

As the Facebook PHP SDK v4.0 gets closer and closer to the next big release of version 4.1 (probably in August or September of 2014), the internal structure keeps getting more and more decoupled. And that's a very, very good thing!

But good things have also recently happened in the 4.0 branch. In version 4.0.9 access token handling has been completely decoupled, and it is now possible to work directly with access tokens with the SDK.

Note: This syntax of the examples used throughout this post are for version 4.0 of the SDK. The syntax will be changing soon in version 4.1.

What is an access token?

An access token is basically a really long ID that is required in order to make calls to the Graph API. The token identifies the following:

It also contains information about the time in seconds until the access token expires and sometimes contains an identifier called a machine_id that identifies the computer that requested the access token. The machine_id is used to verify the access token's authenticity.

Short-lived vs long-lived access tokens

By default, when you request a user access token, Facebook will return a short-lived access token which will expire in 2 hours. Or as the official documentation states, "about an hour or two". I'm not sure the reason for the fuzzy time explanation.

This short amount of time could be problematic if you plan on storing the access token in your database and using it to make requests to Graph later. So you'll need to exchange the short-lived access token for a long-lived access token which will be valid for 2 months before it expires.

In order to extend your short-lived access token with a long-lived access token, you'll need to use the new AccessToken entity from the SDK (see below).

Types of access tokens

There are a number of different access tokens that can be used to interact with Graph. For convenience, Facebook provides an access token tool that lists access tokens for the various apps that you administrate. There's also an access token debugger that will decode an access token and return the underlying identifying data.

But not all access tokens are the same. Depending on what you want to do, you'll need to send a different token with your request to Graph.

User access token

Perhaps the most well-know and widely used access token is the user access token. This is the access token you want to use when making calls to Graph on behalf of a specific user.

A user access token looks like this:

CAABwiWr8tH8BAGKCYOIgoMwJ9T0ZAmJ6KJJNcUjzmftdAOCx1RgzxZAjzGB1s37DDCEoy9r2VgrCLffCTvEGe9cZBZPAwBhygi2ZpTubZC2eCzMe16CLP4Wlc9bStWGwUNYoLEl4dXu4uJl2CCLiFXEtP4GKDv0Gk4s35iXty77KZBx5NYBCcEUs98WjdJQcXLsb1X2ZBaMTW2AZDZN

And a user access token will allow you to:

Obtaining a user access token

User access tokens can be obtained via the Facebook PHP SDK v4 "helpers". The most common helper is the FacebookRedirectLoginHelper which will obtain an access token via a redirect link.

session_start();
use Facebook\FacebookRedirectLoginHelper;
use Facebook\FacebookSDKException;

$helper = new FacebookRedirectLoginHelper('{callback-url}', '{app-id}', '{app-secret}');

try {
    $session = $helper->getSessionFromRedirect();
} catch(FacebookSDKException $e) {
    $session = null;
}

if ($session) {
  // User logged in, get the AccessToken entity.
  $accessToken = $session->getAccessToken();
  // Exchange the short-lived token for a long-lived token.
  $longLivedAccessToken = $accessToken->extend();
  // Now store the long-lived token in the database
  // . . . $db->store($longLivedAccessToken);
  // Make calls to Graph with the long-lived token.
  // . . . 
} else {
  echo '<a href="' . $helper->getLoginUrl() . '">Login with Facebook</a>';
}

Note: The base hostname of the callback URL needs to be defined in the app settings. You'll need to browse to your app in the list of your Facebook apps. Then navigate to the "Settings" tab. In the "App Domains" field, enter any host names you'll be using. Then click, "Add Platform" and choose, "Website". Enter the root URL of your redirect URL in the "Site URL" field.

Page access token

A page access token looks just like a user access token. It also identifies the target page ID. This is the token you want to use to perform actions on behalf of a specific page such as:

Obtaining a page access token

Page access tokens can be obtained from a user who has administrator privileges to the target page and has also authorized your app with the manage_pages permission.

use Facebook\FacebookRequest;

// Assuming $session was obtained from a helper...

// Get a list of pages that this user admins; requires "manage_pages" permission
$request = new FacebookRequest($session, 'GET', '/me/accounts?fields=name,access_token,perms');
$pageList = $request->execute()
  ->getGraphObject()
  ->asArray();

foreach ($pageList as $page) {
  $pageAccessToken = $page['access_token'];
  // Store $pageAccessToken and/or
  // send requests to Graph on behalf of the page
}

The page access tokens that are returned from the /me/accounts endpoint will expire by default if you used a short-lived user access token to obtain them. If you used a long-lived user access token to obtain them, the /me/accounts endpoint will return page access tokens that never expire.

You'll also notice a perms array is returned that lists the administrative permissions that the user has on this page.

App access token

An app access token looks like this:

1234567890|EnEYhJBbcc-gm84CeUivNgC0bZZ

The token is made up of the app ID and the app secret or a valid hash of the app secret. An app access token will allow you to manage the app information including:

Obtaining an app access token

App access tokens don't require any calls to Facebook to obtain. You can make an access token by concatenating the app ID with the app secret and using a pipe delimiter.

{app-id}|{app-secret}

App access tokens don't expire. And since they contain the app secret, you never want to use them on the client side.

The new AccessToken entity

You saw it first in the Facebook Query Builder and now the AccessToken entity has been ported into the official SDK.

Extending a short-lived access token

Once you obtain a valid FacebookSession with the redirect, canvas or javascript helper, you can use getAccessToken() to get the AccessToken entity. Since the first access token you receive will be short-lived, you can easily extend() it to make a long-lived access token.

use Facebook\FacebookSDKException;

// Assuming $session was obtained from a helper...

// Get the AccessToken entity.
$accessToken = $session->getAccessToken();

try {
  // Exchange the short-lived token for a long-lived token.
  $longLivedAccessToken = $accessToken->extend();
} catch(FacebookSDKException $e) {
  echo 'Error extending short-lived access token: ' . $e->getMessage();
  exit;
}

// Now store the long lived token in the database
// . . . $db->store($longLivedAccessToken);
// Make calls to Graph with the long lived token.
// . . . 

Getting detailed information about an access token

The Graph API has a useful /debug_token endpoint that you can use to get information about an access token. And the SDK supports this functionality right out of the box.

use Facebook\Entities\AccessToken;
use Facebook\FacebookSDKException;

$accessToken = new AccessToken('{my-access-token}');

try {
  // Get info about the token
  // Returns a GraphSessionInfo object
  $accessTokenInfo = $accessToken->getInfo();
} catch(FacebookSDKException $e) {
  echo 'Error getting access token info: ' . $e->getMessage();
  exit;
}

// Dump the info about the token
var_dump($accessTokenInfo->asArray());

Of course if you just want to debug a token while you're developing your app, you can always use the convenient debugger provided by Facebook.

Best practices for maintaining long loved access tokens over time

If your app is sending requests with a long-lived access token to the Graph API on behalf of your users frequently, your app is at risk of being flagged for spam. In order to avoid this, you can use a code to get new long-lived tokens.

The basic flow goes something like this:

  1. Retrieve the long-lived user access token from your database.
  2. Use the long-lived token to request a code.
  3. Use the code to request a new long-lived access token.
  4. Use the new long-lived access token to make calls to Graph on the user's behalf.
use Facebook\FacebookSession;
use Facebook\FacebookRequest;
use Facebook\Entities\AccessToken;
use Facebook\FacebookSDKException;

$longLivedAccessToken = new AccessToken('{long-lived-access-token}');

try {
  // Get a code from a long-lived access token
  $code = AccessToken::getCodeFromAccessToken($longLivedAccessToken);
} catch(FacebookSDKException $e) {
  echo 'Error getting code: ' . $e->getMessage();
  exit;
}

try {
  // Get a new long-lived access token from the code
  $newLongLivedAccessToken = AccessToken::getAccessTokenFromCode($code);
} catch(FacebookSDKException $e) {
  echo 'Error getting a new long-lived access token: ' . $e->getMessage();
  exit;
}

// Make calls to Graph using $shortLivedAccessToken
$session = new FacebookSession($newLongLivedAccessToken);

$request = new FacebookRequest($session, 'GET', '/me');
$userData = $request->execute()
  ->getGraphObject()
  ->asArray();

var_dump($userData);

<<EOF;

As you can see access tokens aren't as confusing as they seem at first. Since the SDK makes it so easy to handle access tokens, the hardest part on your end is figuring out which access token you'll need to solve your particular problem.

If you want to dive deeper, check out the official access token documentation on Facebook.

If you found this guide helpful, say, "Hi" on twitter! I'd love to hear from you. :)