7

Hello i'm trying to use facebook server-side authenticaion to get the access token but keep getting errors thrown at me.

I am using the bellow:

$app_id = "YOUR_APP_ID";
   $app_secret = "YOUR_APP_SECRET";
   $my_url = "YOUR_URL";

   session_start();
   $code = $_REQUEST["code"];

   if(empty($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>");
   }

   if($_REQUEST['state'] == $_SESSION['state']) {
     $token_url = "https://graph.facebook.com/oauth/access_token?"
       . "client_id=" . $app_id . "&redirect_uri=" . urlencode($my_url)
       . "&client_secret=" . $app_secret . "&code=" . $code;

     $response = file_get_contents($token_url);
     $params = null;
     parse_str($response, $params);

     $graph_url = "https://graph.facebook.com/me?access_token=" 
       . $params['access_token'];

     $user = json_decode(file_get_contents($graph_url));
     echo("Hello " . $user->name);
   }
   else {
     echo("The state does not match. You may be a victim of CSRF.");
   }

App ID and APP Secret have been removed so dont worry about that part. I get errors about the get_file_contents time out.

[function.file-get-contents]: failed to open stream: Connection timed out

Is there another or better way of getting the access tokens?

Bellow is the version i have tried including the cURL idea:

function get_data_cURL($url)
{
  $ch = curl_init();
  $timeout = 5;
  curl_setopt($ch,CURLOPT_URL,$url);
  curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
  curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,$timeout);
  $data = curl_exec($ch);
  curl_close($ch);
  return $data;
}

function getAccessToken(){
    $app_id = FB_APP_ID;
    $app_secret = FB_SECRET_ID;
    $canvas_URL = FB_CANVAS_URL;

    session_start();
    $code = $_REQUEST["code"];

    if(empty($code)) {
      $_SESSION['state'] = md5(uniqid(rand(), TRUE)); //CSRF protection
      $dialog_url = "https://www.facebook.com/dialog/oauth?client_id=" 
        . $app_id . "&redirect_uri=" . urlencode($canvas_URL) . "&state="
        . $_SESSION['state'];

      echo("<script> top.location.href='" . $dialog_url . "'</script>");
    }

    if($_REQUEST['state'] == $_SESSION['state']) {
      $token_url = "https://graph.facebook.com/oauth/access_token?"
        . "client_id=" . $app_id . "&redirect_uri=" . urlencode($canvas_URL)
        . "&client_secret=" . $app_secret . "&code=" . $code;

     $returned_content = get_data_cURL($token_url);
    echo'Well Done! - '.$returned_content;

    }
    else {
      echo("The state does not match. You may be a victim of CSRF.");
    }
}

Details:

App Settings - Canvas URL: http://www.apps.elistone.co.uk/DrawMyFriend/

FB_APP_ID = The Facebook App ID
FB_SECRET_ID = The Facebook Secret ID
FB_CANVAS_URL = http://www.apps.elistone.co.uk/DrawMyFriend/

Even with this update i still get this error:

Old ERROR

Well Done! - {"error":{"message":"Error validating verification code.","type":"OAuthException","code":100}}

New ERROR

This seems to be caused by the redirect removing the state code.

The state does not match. You may be a victim of CSRF. - 193c791ddd71c3fd84d411db5554c315 (state code)

I have also tried bypassing the CSRF protection by changing:

if($_REQUEST['state'] == $_SESSION['state'])

TO:

 if(!empty($code))

But this still gives the old error problem, I have heard it is caused by something in the redirect link but im not sure how to fix it.

PROBLEM SOLVED

After trying along time i have resulted to using the PHP SDK using the below to get the user access token:

$app_id = FB_APP_ID;
$app_secret = FB_SECRET_ID;
$canvas_URL = FB_PAGE_URL;
$code = $_REQUEST["code"];

if(empty($code)) {
  $_SESSION['state'] = md5(uniqid(rand(), TRUE)); //CSRF protection
  $dialog_url = "https://www.facebook.com/dialog/oauth?client_id=" 
    . $app_id . "&redirect_uri=" . $canvas_URL . "&state="
    . $_SESSION['state'];

  echo("<script> top.location.href='" . $dialog_url . "'</script>");
}
if($_REQUEST['state'] == $_SESSION['state']) {
$facebook->api('oauth/access_token', array(
    'client_id'     => FB_APP_ID,
    'client_secret' => FB_SECRET_ID,
    'type'          => 'client_cred',
    'code'          => $code,
));
$token = $facebook->getAccessToken();
echo$token;
}

I am now going to turn this into some sorta function. Thank you very much for everyones time and help.

Hope this helps people in need in the future (unless Facebook changes everything suddenly)

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Eli Stone
  • 1,515
  • 4
  • 33
  • 57
  • Any reason you don't want to use the Facebook PHP SDK? – phwd Jun 02 '12 at 12:42
  • @phwd The reason why i am not using the PHP SDK is as that is giving me the application access token not the user access token which is what i need to do what i want. – Eli Stone Jun 02 '12 at 15:36

2 Answers2

7

I recommend you to use PHP SDK library for communicating with Facebook API. And simply use getAccessToken() or getAccessTokenFromCode() methods.

UPDATE

To retrieve user access token you have to send oauth request before getting access token. Details in answer update:

    $facebook->api('oauth/access_token', array(
        'client_id'     => APP_ID,
        'client_secret' => APP_SECRET,
        'type'          => 'client_cred',
        'code'          => $code,
    ));
    $token = $facebook->getAccessToken();
tttony
  • 4,944
  • 4
  • 26
  • 41
Oleg
  • 7,070
  • 4
  • 47
  • 49
  • getAccessToken() currently only gives me the application access token which is not good enough for what i need. I wish to require the user access token. How would i go about setting it up to do that? – Eli Stone Jun 04 '12 at 08:52
  • Use `getUserAccessToken()` method for that – Oleg Jun 04 '12 at 10:32
  • seems so close but this error: `Fatal error: Call to protected method BaseFacebook::getUserAccessToken()` – Eli Stone Jun 04 '12 at 18:50
  • ok. When you call `getAccessToken()` it first establish access token to be the application access token. Than it tries to get user access token. I.e. you can use `getAccessToken()` and if it can, it would establish user access token. – Oleg Jun 04 '12 at 20:44
  • Yeh I check it out and `getAccessToken()` should be getting the `getUserAccessToken()` if possible but mine only gets the Application access token and nobody seems to know why this is. I can't be the only person with this problem. There must be something wrong.. – Eli Stone Jun 04 '12 at 20:58
  • You have to send oauth request before getting access token. Details in answer update. – Oleg Jun 05 '12 at 08:29
  • Thank you very much, im not sure why that took so long to complete. Adding in working code to my answer. +50 – Eli Stone Jun 05 '12 at 12:54
  • WOW. How come I cannot find any information on getAccessTokenFromCode()? It took me an extra day of research just to find this information! I am doing this: mobile->code->server(api)->code for access token. – Mark Oct 15 '14 at 16:06
2

Two most likely causes of failure at this step are:

  • redirect_uri is missing the trailing '/'
  • redirect_uri in your call to /oauth/access_token doesn't EXACTLY match the redirect_uri you provided to the oauth dialog

In either case, the code verification will fail and you won't get a token,

The 'failed to open stream: Connection timed out' error probably isn't related to that though, it usually points to a DNS or network error when trying to reach graph.facebook.com from your server

Igy
  • 43,710
  • 8
  • 89
  • 115
  • the redirect_uri = http://www.apps.elistone.co.uk/DrawMyFriend/ so it does having the trailing slash. From what i can see the uri is exactly the same.. So what is missing. – Eli Stone Jun 02 '12 at 18:31