Looking for information on expired access tokens? Try our documentation on the topic.

One of the most frequently asked for “How-To” requests from developers is how to handle invalid access tokens. Access tokens for users can become invalid due to various reasons. In most cases, they can expire if it’s past the time specified by the ‘expires’ field (by default access token have a 2 hour lifetime). What many developers do not realize is that an access token can also expire if a user changes her password, logs out or if she de-authorizes the app via the App Dashboard. It is very important that your apps handle such situations. If your access token expires, you need to reacquire a valid access token.

This post will walk you through how you can ensure that you are handling and recovering from these situations gracefully. It assumes that you are familiar with our server-side authentication flow.

We will discuss 4 different scenarios:

  1. The token expires after expires time (2 hours is the default).
  2. The user changes her password which invalidates the access token.
  3. The user de-authorizes your app.
  4. The user logs out of Facebook.

Token expires after expires time

This scenario refers to the use case where a user has authorized your app in the past, but the access token that you were issued has expired.

When you try to make Graph API call on her behalf you will get an HTTP 400 with the following error in the body:

{ 
  error: {
    type: "OAuthException",
    message: "Session has expired at unix time 
      SOME_TIME. The current unix time is SOME_TIME.”
  }, 
} 

Scenario 2: User changes her password

This scenario refers to use case where a user has authorized your app in the past and then she changes the password associated with her Facebook account. In this scenario, when you try to make Graph API call on her behalf you will get an HTTP 400 with the following error in the body:

{ 
  error: {
    type: "OAuthException",
    message: "The session has been invalidated because 
      the user has changed the password.",
  }, 
}

Please note that you will receive this message even if your app was granted the offline_access permission if the user changed their password.

Scenario 3: User de-authorizes your app

This scenario refers to a use case where a user has authorized your app in the past, but then she de-authorizes your app by going to the App Dashboard. In this scenario when you try to make a Graph API call on her behalf you will get a HTTP 400 with the following error in the body:

{
  error: {
    type: "OAuthException",
    message: "Error validating access token: USER_ID
      has not authorized application APP_ID",
  },
}

Please note that even if the user had authorized your app with the offline_access permission access tokens will become invalid if the user de-authorizes your app.

Scenario 4: User logs out of Facebook

This scenario refers to a use case where a user has authorized your app in the past and then she logs out of Facebook. If the user authorized your app with the offline_access permission then the Graph API call works as expected. If the user did not grant this permission and you try to make a Graph API call on behalf of the user, you will get an HTTP 400 with the following error in the body:

{
  "error": {
    "type":"OAuthException","message":"Error validating 
      access token: The session is invalid because the 
      user logged out."
   }
}

Solution (for all scenarios)

To ensure the best experience for your users, your app needs to be prepared to catch errors for the above scenarios. The following PHP code shows you how to handle these errors and retrieve a new access token.

When you redirect the user to the auth dialog, the user is not prompted for permissions if the user has already authorized your application. Facebook will return you a valid access token without any user facing dialog. However if the user has de-authorized your application then the user will need to re-authorize your application for you to get the access_token.

<?php
  $app_id = "YOUR_APP_ID";
  $app_secret = "YOUR_APP_SECRET"; 
  $my_url = "YOUR_POST_LOGIN_URL";
     
  // known valid access token stored in a database 
  $access_token = "YOUR_STORED_ACCESS_TOKEN";

  $code = $_REQUEST["code"];
    
  // If we get a code, it means that we have re-authed the user 
  //and can get a valid access_token. 
  if (isset($code)) {
    $token_url="https://graph.facebook.com/oauth/access_token?client_id="
      . $app_id . "&redirect_uri=" . urlencode($my_url) 
      . "&client_secret=" . $app_secret 
      . "&code=" . $code . "&display=popup";
    $response = file_get_contents($token_url);
    $params = null;
    parse_str($response, $params);
    $access_token = $params['access_token'];
  }

        
  // Attempt to query the graph:
  $graph_url = "https://graph.facebook.com/me?"
    . "access_token=" . $access_token;
  $response = curl_get_file_contents($graph_url);
  $decoded_response = json_decode($response);
    
  //Check for errors 
  if ($decoded_response->error) {
  // check to see if this is an oAuth error:
    if ($decoded_response->error->type== "OAuthException") {
      // Retrieving a valid access token. 
      $dialog_url= "https://www.facebook.com/dialog/oauth?"
        . "client_id=" . $app_id 
        . "&redirect_uri=" . urlencode($my_url);
      echo("<script> top.location.href='" . $dialog_url 
      . "'</script>");
    }
    else {
      echo "other error has happened";
    }
  } 
  else {
  // success
    echo("success" . $decoded_response->name);
    echo($access_token);
  }

  // note this wrapper function exists in order to circumvent PHP’s 
  //strict obeying of HTTP error codes.  In this case, Facebook 
  //returns error code 400 which PHP obeys and wipes out 
  //the response.
  function curl_get_file_contents($URL) {
    $c = curl_init();
    curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($c, CURLOPT_URL, $URL);
    $contents = curl_exec($c);
    $err  = curl_getinfo($c,CURLINFO_HTTP_CODE);
    curl_close($c);
    if ($contents) return $contents;
    else return FALSE;
  }
?>

Ankur Pansari, a Partner Engineer, hopes this how-to post helps you handle invalid access token scenarios gracefully.