New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Facebook SDK returned an error: Cross-site request forgery validation failed. Required param "state" missing. #473

Closed
tatters1979 opened this Issue Jul 21, 2015 · 50 comments

Comments

Projects
None yet
@tatters1979

tatters1979 commented Jul 21, 2015

Hi, I've moved to the latest version of the SDK and tried the simple login example for starters and it was working fine a few days ago. However I now get the following error:

Facebook SDK returned an error: Cross-site request forgery validation failed. Required param "state" missing.

I can't figure out the problem, I've had a look at the following section of the Helper.

 /**
 * Validate the request against a cross-site request forgery.
 *
 * @throws FacebookSDKException
 */
protected function validateCsrf()
{
    $state = $this->getState();
    $savedState = $this->persistentDataHandler->get('state');

   if (!$state || !$savedState) {
        throw new FacebookSDKException('Cross-site request forgery validation failed. Required param "state" missing.');
    }

    $savedLen = strlen($savedState);
    $givenLen = strlen($state);

    if ($savedLen !== $givenLen) {
        throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
    }

    $result = 0;
    for ($i = 0; $i < $savedLen; $i++) {
        $result |= ord($state[$i]) ^ ord($savedState[$i]);
    }

    if ($result !== 0) {
        throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
    }
}
@SammyK

This comment has been minimized.

Show comment
Hide comment
@SammyK

SammyK Jul 21, 2015

Collaborator

Can you provide the snippet of code that's causing the error?

Collaborator

SammyK commented Jul 21, 2015

Can you provide the snippet of code that's causing the error?

@tatters1979

This comment has been minimized.

Show comment
Hide comment
@tatters1979

tatters1979 Jul 21, 2015

This is the callback php from the example in the docs, thanks for the quick response:

<?php
session_start(); //Session should be active

require_once __DIR__ . "/facebook/autoload.php"; //include autoload from SDK folder

$fb = new Facebook\Facebook([
  'app_id' => 'XXXXXXXXX',
  'app_secret' => 'XXXXXXXX',
  'default_graph_version' => 'v2.3',
  ]);

$helper = $fb->getRedirectLoginHelper();

try {
  $accessToken = $helper->getAccessToken();
} catch(Facebook\Exceptions\FacebookResponseException $e) {
  // When Graph returns an error
  echo 'Graph returned an error: ' . $e->getMessage();
  exit;
} catch(Facebook\Exceptions\FacebookSDKException $e) {
  // When validation fails or other local issues
  echo 'Facebook SDK returned an error: ' . $e->getMessage();
  exit;
}

if (! isset($accessToken)) {
  if ($helper->getError()) {
    header('HTTP/1.0 401 Unauthorized');
    echo "Error: " . $helper->getError() . "\n";
    echo "Error Code: " . $helper->getErrorCode() . "\n";
    echo "Error Reason: " . $helper->getErrorReason() . "\n";
    echo "Error Description: " . $helper->getErrorDescription() . "\n";
  } else {
    header('HTTP/1.0 400 Bad Request');
    echo 'Bad request';
  }
  exit;
}

// Logged in
echo '<h3>Access Token</h3>';
var_dump($accessToken->getValue());

   // The OAuth 2.0 client handler helps us manage access tokens
  $oAuth2Client = $fb->getOAuth2Client();

  // Get the access token metadata from /debug_token
  $tokenMetadata = $oAuth2Client->debugToken($accessToken);
  echo '<h3>Metadata</h3>';
  var_dump($tokenMetadata);

  // Validation (these will throw FacebookSDKException's when they fail)
  $tokenMetadata->validateAppId($config['app_id']);
  // If you know the user ID this access token belongs to, you can validate it here
  //$tokenMetadata->validateUserId('123');
  $tokenMetadata->validateExpiration();

  if (! $accessToken->isLongLived()) {
    // Exchanges a short-lived access token for a long-lived one
    try {
   $accessToken = $oAuth2Client->getLongLivedAccessToken($accessToken);
  } catch (Facebook\Exceptions\FacebookSDKException $e) {
    echo "<p>Error getting long-lived access token: " . $helper->getMessage() . "</p>\n\n";
    exit;
  }

 echo '<h3>Long-lived</h3>';
 var_dump($accessToken->getValue());
}

$_SESSION['fb_access_token'] = (string) $accessToken;

// User is logged in with a long-lived access token.
// You can redirect them to a members-only page.
//header('Location: https://example.com/members.php');

tatters1979 commented Jul 21, 2015

This is the callback php from the example in the docs, thanks for the quick response:

<?php
session_start(); //Session should be active

require_once __DIR__ . "/facebook/autoload.php"; //include autoload from SDK folder

$fb = new Facebook\Facebook([
  'app_id' => 'XXXXXXXXX',
  'app_secret' => 'XXXXXXXX',
  'default_graph_version' => 'v2.3',
  ]);

$helper = $fb->getRedirectLoginHelper();

try {
  $accessToken = $helper->getAccessToken();
} catch(Facebook\Exceptions\FacebookResponseException $e) {
  // When Graph returns an error
  echo 'Graph returned an error: ' . $e->getMessage();
  exit;
} catch(Facebook\Exceptions\FacebookSDKException $e) {
  // When validation fails or other local issues
  echo 'Facebook SDK returned an error: ' . $e->getMessage();
  exit;
}

if (! isset($accessToken)) {
  if ($helper->getError()) {
    header('HTTP/1.0 401 Unauthorized');
    echo "Error: " . $helper->getError() . "\n";
    echo "Error Code: " . $helper->getErrorCode() . "\n";
    echo "Error Reason: " . $helper->getErrorReason() . "\n";
    echo "Error Description: " . $helper->getErrorDescription() . "\n";
  } else {
    header('HTTP/1.0 400 Bad Request');
    echo 'Bad request';
  }
  exit;
}

// Logged in
echo '<h3>Access Token</h3>';
var_dump($accessToken->getValue());

   // The OAuth 2.0 client handler helps us manage access tokens
  $oAuth2Client = $fb->getOAuth2Client();

  // Get the access token metadata from /debug_token
  $tokenMetadata = $oAuth2Client->debugToken($accessToken);
  echo '<h3>Metadata</h3>';
  var_dump($tokenMetadata);

  // Validation (these will throw FacebookSDKException's when they fail)
  $tokenMetadata->validateAppId($config['app_id']);
  // If you know the user ID this access token belongs to, you can validate it here
  //$tokenMetadata->validateUserId('123');
  $tokenMetadata->validateExpiration();

  if (! $accessToken->isLongLived()) {
    // Exchanges a short-lived access token for a long-lived one
    try {
   $accessToken = $oAuth2Client->getLongLivedAccessToken($accessToken);
  } catch (Facebook\Exceptions\FacebookSDKException $e) {
    echo "<p>Error getting long-lived access token: " . $helper->getMessage() . "</p>\n\n";
    exit;
  }

 echo '<h3>Long-lived</h3>';
 var_dump($accessToken->getValue());
}

$_SESSION['fb_access_token'] = (string) $accessToken;

// User is logged in with a long-lived access token.
// You can redirect them to a members-only page.
//header('Location: https://example.com/members.php');
@SammyK

This comment has been minimized.

Show comment
Hide comment
@SammyK

SammyK Jul 21, 2015

Collaborator

After the catch(Facebook\Exceptions\FacebookResponseException $e) line can you var_dump() any possible user errors?

var_dump($helper->getError());
Collaborator

SammyK commented Jul 21, 2015

After the catch(Facebook\Exceptions\FacebookResponseException $e) line can you var_dump() any possible user errors?

var_dump($helper->getError());
@tatters1979

This comment has been minimized.

Show comment
Hide comment
@tatters1979

tatters1979 Jul 21, 2015

Changed to the following, no new errors?

try {
  $accessToken = $helper->getAccessToken();
} catch(Facebook\Exceptions\FacebookResponseException $e) {
  // When Graph returns an error
  var_dump($helper->getError());
  echo 'Graph returned an error: ' . $e->getMessage();
  exit;
} catch(Facebook\Exceptions\FacebookSDKException $e) {
  // When validation fails or other local issues
 echo 'Facebook SDK returned an error: ' . $e->getMessage();
 exit;
}

tatters1979 commented Jul 21, 2015

Changed to the following, no new errors?

try {
  $accessToken = $helper->getAccessToken();
} catch(Facebook\Exceptions\FacebookResponseException $e) {
  // When Graph returns an error
  var_dump($helper->getError());
  echo 'Graph returned an error: ' . $e->getMessage();
  exit;
} catch(Facebook\Exceptions\FacebookSDKException $e) {
  // When validation fails or other local issues
 echo 'Facebook SDK returned an error: ' . $e->getMessage();
 exit;
}
@SammyK

This comment has been minimized.

Show comment
Hide comment
@SammyK

SammyK Jul 22, 2015

Collaborator

Sorry, I meant to paste that after the catch(Facebook\Exceptions\FacebookSDKException $e) line. :) I'm curious if you'll see NULL just before the error message.

Can you paste in the callback URL that Facebook is redirecting to with the value of the code= param removed?

Collaborator

SammyK commented Jul 22, 2015

Sorry, I meant to paste that after the catch(Facebook\Exceptions\FacebookSDKException $e) line. :) I'm curious if you'll see NULL just before the error message.

Can you paste in the callback URL that Facebook is redirecting to with the value of the code= param removed?

@tatters1979

This comment has been minimized.

Show comment
Hide comment
@tatters1979

tatters1979 Jul 22, 2015

Hi Sammy,

Thanks, I dropped that to the correct line and "NULL" was returned along with the original error.

Facebook SDK returned an error: Cross-site request forgery validation failed. Required param "state" missing.NULL 

try {
  $accessToken = $helper->getAccessToken();
} catch(Facebook\Exceptions\FacebookResponseException $e) {
  // When Graph returns an error
  echo 'Graph returned an error: ' . $e->getMessage();
  exit;
} catch(Facebook\Exceptions\FacebookSDKException $e) {
  // When validation fails or other local issues
 echo 'Facebook SDK returned an error: ' . $e->getMessage();
 var_dump($helper->getError());
 exit;
}

I found a similar question on Stack Overflow and he said to solve this problem he changed the UTF-8 to UTF8 w/o BOM. Not sure how this affect the above but he said it worked on his code?

http://stackoverflow.com/questions/31520593/facebook-php-sdk-5-api-2-4-cross-site-request-forgery-validation-failed-r/31542061?noredirect=1#comment51055949_31542061

tatters1979 commented Jul 22, 2015

Hi Sammy,

Thanks, I dropped that to the correct line and "NULL" was returned along with the original error.

Facebook SDK returned an error: Cross-site request forgery validation failed. Required param "state" missing.NULL 

try {
  $accessToken = $helper->getAccessToken();
} catch(Facebook\Exceptions\FacebookResponseException $e) {
  // When Graph returns an error
  echo 'Graph returned an error: ' . $e->getMessage();
  exit;
} catch(Facebook\Exceptions\FacebookSDKException $e) {
  // When validation fails or other local issues
 echo 'Facebook SDK returned an error: ' . $e->getMessage();
 var_dump($helper->getError());
 exit;
}

I found a similar question on Stack Overflow and he said to solve this problem he changed the UTF-8 to UTF8 w/o BOM. Not sure how this affect the above but he said it worked on his code?

http://stackoverflow.com/questions/31520593/facebook-php-sdk-5-api-2-4-cross-site-request-forgery-validation-failed-r/31542061?noredirect=1#comment51055949_31542061

@SammyK

This comment has been minimized.

Show comment
Hide comment
@SammyK

SammyK Jul 22, 2015

Collaborator

Do you have display errors on? If not, for testing add these lines at the top of your script after the opening <?php tag:

error_reporting(E_ALL);
ini_set("display_errors", 1);

If you had a BOM in your file you should see an error about not being able to start the session since headers have been sent. If you see that, you'll need to remove or ignore the BOM.

If that doesn't help, can you change the var_dump() you added to this?

var_dump($helper->getPersistentDataHandler());

Just want to make sure the proper handler is being used.

Collaborator

SammyK commented Jul 22, 2015

Do you have display errors on? If not, for testing add these lines at the top of your script after the opening <?php tag:

error_reporting(E_ALL);
ini_set("display_errors", 1);

If you had a BOM in your file you should see an error about not being able to start the session since headers have been sent. If you see that, you'll need to remove or ignore the BOM.

If that doesn't help, can you change the var_dump() you added to this?

var_dump($helper->getPersistentDataHandler());

Just want to make sure the proper handler is being used.

@tatters1979

This comment has been minimized.

Show comment
Hide comment
@tatters1979

tatters1979 Jul 22, 2015

Added those changes and got a response:

object(Facebook\PersistentData\FacebookSessionPersistentDataHandler)#9 (1) { ["sessionPrefix":protected]=> string(6) "FBRLH_" }

Facebook SDK returned an error: Cross-site request forgery validation failed. Required param "state" missing.

tatters1979 commented Jul 22, 2015

Added those changes and got a response:

object(Facebook\PersistentData\FacebookSessionPersistentDataHandler)#9 (1) { ["sessionPrefix":protected]=> string(6) "FBRLH_" }

Facebook SDK returned an error: Cross-site request forgery validation failed. Required param "state" missing.

@SammyK

This comment has been minimized.

Show comment
Hide comment
@SammyK

SammyK Jul 22, 2015

Collaborator

Are you doing any load-balancing on the server side? I curious why your sessions seem to not be working. How about var dumping your $_GET & $_SESSION. Do you see the state param in either?

var_dump($_GET, $_SESSION);
Collaborator

SammyK commented Jul 22, 2015

Are you doing any load-balancing on the server side? I curious why your sessions seem to not be working. How about var dumping your $_GET & $_SESSION. Do you see the state param in either?

var_dump($_GET, $_SESSION);
@tatters1979

This comment has been minimized.

Show comment
Hide comment
@tatters1979

tatters1979 Jul 22, 2015

My service provider is Network Solutions and sessions have always been fine (I use them for the Twitter API)?

var_dump($_GET);

returned the state param and the code param

var_dump($_SESSION);

returns nothing?

tatters1979 commented Jul 22, 2015

My service provider is Network Solutions and sessions have always been fine (I use them for the Twitter API)?

var_dump($_GET);

returned the state param and the code param

var_dump($_SESSION);

returns nothing?

@SammyK

This comment has been minimized.

Show comment
Hide comment
@SammyK

SammyK Jul 22, 2015

Collaborator

I'm thinking this is related to #470. What do you guys think? cc @yguedidi @devmsh

Collaborator

SammyK commented Jul 22, 2015

I'm thinking this is related to #470. What do you guys think? cc @yguedidi @devmsh

@tatters1979

This comment has been minimized.

Show comment
Hide comment
@tatters1979

tatters1979 Jul 22, 2015

hmm it does sound like it...I take there's no work around available?

tatters1979 commented Jul 22, 2015

hmm it does sound like it...I take there's no work around available?

@SammyK

This comment has been minimized.

Show comment
Hide comment
@SammyK

SammyK Jul 22, 2015

Collaborator

Not yet. Got to narrow the bug down to what's causing people's sessions to reset on the callback. :/

Collaborator

SammyK commented Jul 22, 2015

Not yet. Got to narrow the bug down to what's causing people's sessions to reset on the callback. :/

@tatters1979

This comment has been minimized.

Show comment
Hide comment
@tatters1979

tatters1979 Jul 22, 2015

No worries, I'll keep checking back for any updates....Thanks for your help SammyK.

tatters1979 commented Jul 22, 2015

No worries, I'll keep checking back for any updates....Thanks for your help SammyK.

@SammyK

This comment has been minimized.

Show comment
Hide comment
@SammyK

SammyK Jul 22, 2015

Collaborator

Np! Hopefully we'll be able to nip this one in the bud.

Collaborator

SammyK commented Jul 22, 2015

Np! Hopefully we'll be able to nip this one in the bud.

@eduardomazolini

This comment has been minimized.

Show comment
Hide comment
@eduardomazolini

eduardomazolini Jul 25, 2015

I've been with the same problem, I lost more than a day.
Maybe I've just done something stupid, but I walked into my site without putting "www" and put "www" in the callback URL.
The browser created two different cookies.

$currentCookieParams = session_get_cookie_params();
$rootDomain = '.example.com';
session_set_cookie_params(
$currentCookieParams["lifetime"],
$currentCookieParams["path"],
$rootDomain,
$currentCookieParams["secure"],
$currentCookieParams["httponly"]
);
session_start();

eduardomazolini commented Jul 25, 2015

I've been with the same problem, I lost more than a day.
Maybe I've just done something stupid, but I walked into my site without putting "www" and put "www" in the callback URL.
The browser created two different cookies.

$currentCookieParams = session_get_cookie_params();
$rootDomain = '.example.com';
session_set_cookie_params(
$currentCookieParams["lifetime"],
$currentCookieParams["path"],
$rootDomain,
$currentCookieParams["secure"],
$currentCookieParams["httponly"]
);
session_start();

@tatters1979

This comment has been minimized.

Show comment
Hide comment
@tatters1979

tatters1979 Jul 27, 2015

@SammyK Couple of developments after looking at the code.

I think the documentation on the Facebook pages might be out of date in a few places (examples).

$fb = new Facebook\Facebook([
  'app_id' => 'XXXXXXXXX',
  'app_secret' => 'XXXXXXXX',
  'default_graph_version' => 'v2.4',
  ]);

I changed the graph version from v2.2 from v2.4 on the login.php and fb-callback.php files even though the facebook pages says 2.3 is the latest version?

I also added "www" to the call back URL on the login.php file and Oauth field in the App settings.

This seems to be working now? I'm not sure what did it? However the Metadata files are now throwing a fatal error/uncaught exception:

Fatal error: Uncaught exception 'Facebook\Exceptions\FacebookSDKException' with
message 'Access token metadata contains unexpected app ID.'
in /path/htdocs/src/Facebook/Authentication/AccessTokenMetadata.php:329 Stack trace:
#0 /path/htdocs/fb-callback.php(65): Facebook\Authentication\AccessTokenMetadata
>validateAppId(NULL) #1 {main} thrown 
in /path/htdocs/src/Facebook/Authentication/AccessTokenMetadata.php on line 329

One problem solved,another one created.

tatters1979 commented Jul 27, 2015

@SammyK Couple of developments after looking at the code.

I think the documentation on the Facebook pages might be out of date in a few places (examples).

$fb = new Facebook\Facebook([
  'app_id' => 'XXXXXXXXX',
  'app_secret' => 'XXXXXXXX',
  'default_graph_version' => 'v2.4',
  ]);

I changed the graph version from v2.2 from v2.4 on the login.php and fb-callback.php files even though the facebook pages says 2.3 is the latest version?

I also added "www" to the call back URL on the login.php file and Oauth field in the App settings.

This seems to be working now? I'm not sure what did it? However the Metadata files are now throwing a fatal error/uncaught exception:

Fatal error: Uncaught exception 'Facebook\Exceptions\FacebookSDKException' with
message 'Access token metadata contains unexpected app ID.'
in /path/htdocs/src/Facebook/Authentication/AccessTokenMetadata.php:329 Stack trace:
#0 /path/htdocs/fb-callback.php(65): Facebook\Authentication\AccessTokenMetadata
>validateAppId(NULL) #1 {main} thrown 
in /path/htdocs/src/Facebook/Authentication/AccessTokenMetadata.php on line 329

One problem solved,another one created.

@tatters1979

This comment has been minimized.

Show comment
Hide comment
@tatters1979

tatters1979 Jul 27, 2015

@SammyK Problem solved, I removed the second section of the old code on the example asking for a long lived token and it works.

I also added the code for retreiving user details and for posting an image and both worked. So it looks like a few examples are out of date on the FB developer pages, this might trip a few noobs like myself up.

One more thing, does a POST from a form for images - $_FILES['image_file']['name']; work on the image upload? I had to include the full file path for an image I had in my root folder...instead of img/rest.jpg?

Thanks for your help.

tatters1979 commented Jul 27, 2015

@SammyK Problem solved, I removed the second section of the old code on the example asking for a long lived token and it works.

I also added the code for retreiving user details and for posting an image and both worked. So it looks like a few examples are out of date on the FB developer pages, this might trip a few noobs like myself up.

One more thing, does a POST from a form for images - $_FILES['image_file']['name']; work on the image upload? I had to include the full file path for an image I had in my root folder...instead of img/rest.jpg?

Thanks for your help.

@SammyK

This comment has been minimized.

Show comment
Hide comment
@SammyK

SammyK Jul 27, 2015

Collaborator

I think the documentation on the Facebook pages might be out of date in a few places

Yeah, I've been meaning to get in there and make some updates. I've also found a few type-o's.

I also added "www" to the call back URL on the login.php file and Oauth field in the App settings

Yeah, if you're using the "www" version to generate the "login link" and you get redirected to the non-www version, you'll run into issues with your session.

But there's still another bug going on with the sessions that's been quite illusive. :/

Access token metadata contains unexpected app ID.

What was the code that was throwing the error? Were you trying to validate the app ID?

does a POST from a form for images - $_FILES['image_file']['name']; work on the image upload?

You can move your file upload to a temp location & then upload it.

$tmpName = $_FILES['image_file']['tmp_name'];
$dest = '/path/to/'.$_FILES['image_file']['name'];

move_uploaded_file($tmpName, $dest);

$data = [
  'message' => 'My awesome photo upload example.',
  'source' => $fb->fileToUpload($dest),
];

$response = $fb->post('/me/photos', $data, '{access-token}');

// Delete the temp file after sending to Facebook
unlink($dest);

Naturally you'd want to validate the upload and all that before blindly moving it around. :)

Collaborator

SammyK commented Jul 27, 2015

I think the documentation on the Facebook pages might be out of date in a few places

Yeah, I've been meaning to get in there and make some updates. I've also found a few type-o's.

I also added "www" to the call back URL on the login.php file and Oauth field in the App settings

Yeah, if you're using the "www" version to generate the "login link" and you get redirected to the non-www version, you'll run into issues with your session.

But there's still another bug going on with the sessions that's been quite illusive. :/

Access token metadata contains unexpected app ID.

What was the code that was throwing the error? Were you trying to validate the app ID?

does a POST from a form for images - $_FILES['image_file']['name']; work on the image upload?

You can move your file upload to a temp location & then upload it.

$tmpName = $_FILES['image_file']['tmp_name'];
$dest = '/path/to/'.$_FILES['image_file']['name'];

move_uploaded_file($tmpName, $dest);

$data = [
  'message' => 'My awesome photo upload example.',
  'source' => $fb->fileToUpload($dest),
];

$response = $fb->post('/me/photos', $data, '{access-token}');

// Delete the temp file after sending to Facebook
unlink($dest);

Naturally you'd want to validate the upload and all that before blindly moving it around. :)

@tatters1979

This comment has been minimized.

Show comment
Hide comment
@tatters1979

tatters1979 Jul 27, 2015

Yeah, I removed the second section of the code and it started working fine (see below).

However my callback doesn't validate (commented out) the access token or exchange it for a long lived one either. It would be nice to get this working but the error is as follows:

Notice: Undefined variable: config in /path/htdocs/fb-callbacks.php on line 68

and the error above re: AccessTokenMetadata.php

// Logged in
echo '<h3>Access Token</h3>';
var_dump($accessToken->getValue());

// The OAuth 2.0 client handler helps us manage access tokens
$oAuth2Client = $fb->getOAuth2Client();

// Get the access token metadata from /debug_token
$tokenMetadata = $oAuth2Client->debugToken($accessToken);
echo '<h3>Metadata</h3>';
var_dump($tokenMetadata);

// Validation (these will throw FacebookSDKException's when they fail)
$tokenMetadata->validateAppId($config['XXXXXXX']);
// Line 68 above - My App ID? If you know the user ID this access token belongs to, you can validate it here
//$tokenMetadata->validateUserId('123');
$tokenMetadata->validateExpiration();

if (! $accessToken->isLongLived()) {
  // Exchanges a short-lived access token for a long-lived one
  try {
    $accessToken = $oAuth2Client->getLongLivedAccessToken($accessToken);
  } catch (Facebook\Exceptions\FacebookSDKException $e) {
    echo "<p>Error getting long-lived access token: " . $helper->getMessage() . "</p>\n\n";
    exit;
  }

  echo '<h3>Long-lived</h3>';
  var_dump($accessToken->getValue());
}

$_SESSION['fb_access_token'] = (string) $accessToken;

tatters1979 commented Jul 27, 2015

Yeah, I removed the second section of the code and it started working fine (see below).

However my callback doesn't validate (commented out) the access token or exchange it for a long lived one either. It would be nice to get this working but the error is as follows:

Notice: Undefined variable: config in /path/htdocs/fb-callbacks.php on line 68

and the error above re: AccessTokenMetadata.php

// Logged in
echo '<h3>Access Token</h3>';
var_dump($accessToken->getValue());

// The OAuth 2.0 client handler helps us manage access tokens
$oAuth2Client = $fb->getOAuth2Client();

// Get the access token metadata from /debug_token
$tokenMetadata = $oAuth2Client->debugToken($accessToken);
echo '<h3>Metadata</h3>';
var_dump($tokenMetadata);

// Validation (these will throw FacebookSDKException's when they fail)
$tokenMetadata->validateAppId($config['XXXXXXX']);
// Line 68 above - My App ID? If you know the user ID this access token belongs to, you can validate it here
//$tokenMetadata->validateUserId('123');
$tokenMetadata->validateExpiration();

if (! $accessToken->isLongLived()) {
  // Exchanges a short-lived access token for a long-lived one
  try {
    $accessToken = $oAuth2Client->getLongLivedAccessToken($accessToken);
  } catch (Facebook\Exceptions\FacebookSDKException $e) {
    echo "<p>Error getting long-lived access token: " . $helper->getMessage() . "</p>\n\n";
    exit;
  }

  echo '<h3>Long-lived</h3>';
  var_dump($accessToken->getValue());
}

$_SESSION['fb_access_token'] = (string) $accessToken;
@SammyK

This comment has been minimized.

Show comment
Hide comment
@SammyK

SammyK Jul 27, 2015

Collaborator

You can delete all these line if you're not trying to validate the access token:

// Validation (these will throw FacebookSDKException's when they fail)
$tokenMetadata->validateAppId($config['XXXXXXX']);
// Line 68 above - My App ID? If you know the user ID this access token belongs to, you can validate it here
//$tokenMetadata->validateUserId('123');
$tokenMetadata->validateExpiration();
Collaborator

SammyK commented Jul 27, 2015

You can delete all these line if you're not trying to validate the access token:

// Validation (these will throw FacebookSDKException's when they fail)
$tokenMetadata->validateAppId($config['XXXXXXX']);
// Line 68 above - My App ID? If you know the user ID this access token belongs to, you can validate it here
//$tokenMetadata->validateUserId('123');
$tokenMetadata->validateExpiration();
@tatters1979

This comment has been minimized.

Show comment
Hide comment
@tatters1979

tatters1979 Jul 27, 2015

That removed the error but the following code echos nothing?

if (! $accessToken->isLongLived()) {
// Exchanges a short-lived access token for a long-lived one
  try {
    $accessToken = $oAuth2Client->getLongLivedAccessToken($accessToken);
  } catch (Facebook\Exceptions\FacebookSDKException $e) {
    echo "<p>Error getting long-lived access token: " . $helper->getMessage() . "</p>\n\n";
    exit;
  }

  echo '<h3>Long-lived</h3>';
  var_dump($accessToken->getValue());
}

tatters1979 commented Jul 27, 2015

That removed the error but the following code echos nothing?

if (! $accessToken->isLongLived()) {
// Exchanges a short-lived access token for a long-lived one
  try {
    $accessToken = $oAuth2Client->getLongLivedAccessToken($accessToken);
  } catch (Facebook\Exceptions\FacebookSDKException $e) {
    echo "<p>Error getting long-lived access token: " . $helper->getMessage() . "</p>\n\n";
    exit;
  }

  echo '<h3>Long-lived</h3>';
  var_dump($accessToken->getValue());
}
@SammyK

This comment has been minimized.

Show comment
Hide comment
@SammyK

SammyK Jul 27, 2015

Collaborator

Then it sounds like the access token you're getting is already long-lived. :)

Collaborator

SammyK commented Jul 27, 2015

Then it sounds like the access token you're getting is already long-lived. :)

@tatters1979

This comment has been minimized.

Show comment
Hide comment
@tatters1979

tatters1979 Jul 27, 2015

That would explain it...Happy days...

Thanks for the tip on the file uploads...worked a treat. Just need to master batch uploads and I think I'm getting somewhere :)

tatters1979 commented Jul 27, 2015

That would explain it...Happy days...

Thanks for the tip on the file uploads...worked a treat. Just need to master batch uploads and I think I'm getting somewhere :)

@tatters1979

This comment has been minimized.

Show comment
Hide comment
@tatters1979

tatters1979 Jul 28, 2015

@SammyK Hope I'm not being a pain. Batch uploads (4 images/photos) are working but it's posting the same picture (the last one) 4 times when I use the following. The comments are all different but the images should be different also?

<?php

require_once __DIR__ . '/src/Facebook/autoload.php';

$fb = new Facebook\Facebook([
  'app_id' => 'XXXXX',
  'app_secret' => 'XXXX',
  'default_graph_version' => 'v2.4',
  ]);

$tmpName1 = $_FILES['image_file1']['tmp_name'];
$dest1 = '/path/htdocs/img/'.$_FILES['image_file1']['name'];
move_uploaded_file($tmpName1, $dest1);

$tmpName2 = $_FILES['image_file2']['tmp_name'];
$dest2 = '/path/htdocs/img/'.$_FILES['image_file2']['name'];
move_uploaded_file($tmpName2, $dest2);

$tmpName3 = $_FILES['image_file3']['tmp_name'];
$dest3 = '/path/htdocs/img/'.$_FILES['image_file3']['name'];
move_uploaded_file($tmpName3, $dest3);

$tmpName4 = $_FILES['image_file4']['tmp_name'];
$dest4 = '/path/htdocs/img/'.$_FILES['image_file4']['name'];
move_uploaded_file($tmpName4, $dest4);

// Since all the requests will be sent on behalf of the same user,
// we'll set the default fallback access token here.
$fb->setDefaultAccessToken($_SESSION['fb_access_token']);

$batch = [
  'photo-one' => $fb->request('POST', '/me/photos', [
      'message' => $_POST['comment1'],
      'source' => $fb->fileToUpload($dest1),
    ]),
  'photo-two' => $fb->request('POST', '/me/photos', [
      'message' => $_POST['comment2'],
      'source' => $fb->fileToUpload($dest2),
    ]),
  'photo-three' => $fb->request('POST', '/me/photos', [
      'message' => $_POST['comment3'],
      'source' => $fb->fileToUpload($dest3),
    ]),
  'photo-four' => $fb->request('POST', '/me/photos', [
      'message' => $_POST['comment4'],
      'source' => $fb->fileToUpload($dest4),
    ]),
];

try {
  $responses = $fb->sendBatchRequest($batch);
} catch(Facebook\Exceptions\FacebookResponseException $e) {
  // When Graph returns an error
  echo 'Graph returned an error: ' . $e->getMessage();
  exit;
} catch(Facebook\Exceptions\FacebookSDKException $e) {
  // When validation fails or other local issues
  echo 'Facebook SDK returned an error: ' . $e->getMessage();
  exit;
}

foreach ($responses as $key => $response) {
  if ($response->isError()) {
    $e = $response->getThrownException();
    echo '<p>Error! Facebook SDK Said: ' . $e->getMessage() . "\n\n";
    echo '<p>Graph Said: ' . "\n\n";
    var_dump($e->getResponse());
  } else {
    echo "<p>(" . $key . ") HTTP status code: " . $response->getHttpStatusCode() . "<br />\n";
    echo "Response: " . $response->getBody() . "</p>\n\n";
    echo "<hr />\n\n";
  }
}

?>

The form is like so:

<form action="fb-batch.php" method="post" enctype="multipart/form-data">
Select image to upload:
<input type="text" name="comment1" />
<input type="file" name="image_file1" id="fileToUpload">
<p></p>
<input type="text" name="comment2" />
<input type="file" name="image_file2" id="fileToUpload">
<p></p>
<input type="text" name="comment3" />
<input type="file" name="image_file3" id="fileToUpload">
<p></p>
<input type="text" name="comment4" />
<input type="file" name="image_file4" id="fileToUpload">
<p></p>
<input type="submit" value="Upload Image" name="submit">
</form>

Many Thanks

tatters1979 commented Jul 28, 2015

@SammyK Hope I'm not being a pain. Batch uploads (4 images/photos) are working but it's posting the same picture (the last one) 4 times when I use the following. The comments are all different but the images should be different also?

<?php

require_once __DIR__ . '/src/Facebook/autoload.php';

$fb = new Facebook\Facebook([
  'app_id' => 'XXXXX',
  'app_secret' => 'XXXX',
  'default_graph_version' => 'v2.4',
  ]);

$tmpName1 = $_FILES['image_file1']['tmp_name'];
$dest1 = '/path/htdocs/img/'.$_FILES['image_file1']['name'];
move_uploaded_file($tmpName1, $dest1);

$tmpName2 = $_FILES['image_file2']['tmp_name'];
$dest2 = '/path/htdocs/img/'.$_FILES['image_file2']['name'];
move_uploaded_file($tmpName2, $dest2);

$tmpName3 = $_FILES['image_file3']['tmp_name'];
$dest3 = '/path/htdocs/img/'.$_FILES['image_file3']['name'];
move_uploaded_file($tmpName3, $dest3);

$tmpName4 = $_FILES['image_file4']['tmp_name'];
$dest4 = '/path/htdocs/img/'.$_FILES['image_file4']['name'];
move_uploaded_file($tmpName4, $dest4);

// Since all the requests will be sent on behalf of the same user,
// we'll set the default fallback access token here.
$fb->setDefaultAccessToken($_SESSION['fb_access_token']);

$batch = [
  'photo-one' => $fb->request('POST', '/me/photos', [
      'message' => $_POST['comment1'],
      'source' => $fb->fileToUpload($dest1),
    ]),
  'photo-two' => $fb->request('POST', '/me/photos', [
      'message' => $_POST['comment2'],
      'source' => $fb->fileToUpload($dest2),
    ]),
  'photo-three' => $fb->request('POST', '/me/photos', [
      'message' => $_POST['comment3'],
      'source' => $fb->fileToUpload($dest3),
    ]),
  'photo-four' => $fb->request('POST', '/me/photos', [
      'message' => $_POST['comment4'],
      'source' => $fb->fileToUpload($dest4),
    ]),
];

try {
  $responses = $fb->sendBatchRequest($batch);
} catch(Facebook\Exceptions\FacebookResponseException $e) {
  // When Graph returns an error
  echo 'Graph returned an error: ' . $e->getMessage();
  exit;
} catch(Facebook\Exceptions\FacebookSDKException $e) {
  // When validation fails or other local issues
  echo 'Facebook SDK returned an error: ' . $e->getMessage();
  exit;
}

foreach ($responses as $key => $response) {
  if ($response->isError()) {
    $e = $response->getThrownException();
    echo '<p>Error! Facebook SDK Said: ' . $e->getMessage() . "\n\n";
    echo '<p>Graph Said: ' . "\n\n";
    var_dump($e->getResponse());
  } else {
    echo "<p>(" . $key . ") HTTP status code: " . $response->getHttpStatusCode() . "<br />\n";
    echo "Response: " . $response->getBody() . "</p>\n\n";
    echo "<hr />\n\n";
  }
}

?>

The form is like so:

<form action="fb-batch.php" method="post" enctype="multipart/form-data">
Select image to upload:
<input type="text" name="comment1" />
<input type="file" name="image_file1" id="fileToUpload">
<p></p>
<input type="text" name="comment2" />
<input type="file" name="image_file2" id="fileToUpload">
<p></p>
<input type="text" name="comment3" />
<input type="file" name="image_file3" id="fileToUpload">
<p></p>
<input type="text" name="comment4" />
<input type="file" name="image_file4" id="fileToUpload">
<p></p>
<input type="submit" value="Upload Image" name="submit">
</form>

Many Thanks

@tatters1979

This comment has been minimized.

Show comment
Hide comment
@tatters1979

tatters1979 Jul 29, 2015

That's now working also...but only when taking photos off a desktop with each photo having a different name. Using an iPhone posts the same image 4 times?

tatters1979 commented Jul 29, 2015

That's now working also...but only when taking photos off a desktop with each photo having a different name. Using an iPhone posts the same image 4 times?

@SammyK

This comment has been minimized.

Show comment
Hide comment
@SammyK

SammyK Jul 29, 2015

Collaborator

Yeah, the move_uploaded_file() function will overwrite the destination if it already exists. So if all your photos are named "photo1.jpg", then they will all be overwritten and the batch will just upload the last uploaded version of the photo.

I'd keep the extension but create a unique name for each uploaded file:

$tmpName1 = $_FILES['image_file1']['tmp_name'];
$ext = pathinfo($_FILES['image_file1']['name'], PATHINFO_EXTENSION);
$dest1 = '/path/htdocs/img/'.uniqid().'.'.$ext;
move_uploaded_file($tmpName1, $dest1);

And don't forget to delete the uploaded files after the batch upload has completed.

unlink($dest1);
unlink($dest2);
// . . . 
Collaborator

SammyK commented Jul 29, 2015

Yeah, the move_uploaded_file() function will overwrite the destination if it already exists. So if all your photos are named "photo1.jpg", then they will all be overwritten and the batch will just upload the last uploaded version of the photo.

I'd keep the extension but create a unique name for each uploaded file:

$tmpName1 = $_FILES['image_file1']['tmp_name'];
$ext = pathinfo($_FILES['image_file1']['name'], PATHINFO_EXTENSION);
$dest1 = '/path/htdocs/img/'.uniqid().'.'.$ext;
move_uploaded_file($tmpName1, $dest1);

And don't forget to delete the uploaded files after the batch upload has completed.

unlink($dest1);
unlink($dest2);
// . . . 
@tatters1979

This comment has been minimized.

Show comment
Hide comment
@tatters1979

tatters1979 Jul 29, 2015

Bingo! Worked like a dream. Thanks again @SammyK

tatters1979 commented Jul 29, 2015

Bingo! Worked like a dream. Thanks again @SammyK

@SammyK

This comment has been minimized.

Show comment
Hide comment
@SammyK

SammyK Jul 29, 2015

Collaborator

Np! Glad you got it working! :)

Collaborator

SammyK commented Jul 29, 2015

Np! Glad you got it working! :)

@gfosco gfosco closed this Aug 3, 2015

@gitscep2015

This comment has been minimized.

Show comment
Hide comment
@gitscep2015

gitscep2015 Aug 19, 2015

Hi,
Facebook SDK latest version returned an error: Cross-site request forgery validation failed. Required param "state" missing in firefox.

I am getting the access token in chrome, but not with firefox. Any ideas.

Facebook App Domains are set to www.domain.com and domain.com
Facebook Site URL is http://www.domain.com
oAuth redirect url is http://www.domain.com/fb-callback.php
Sammy....?

gitscep2015 commented Aug 19, 2015

Hi,
Facebook SDK latest version returned an error: Cross-site request forgery validation failed. Required param "state" missing in firefox.

I am getting the access token in chrome, but not with firefox. Any ideas.

Facebook App Domains are set to www.domain.com and domain.com
Facebook Site URL is http://www.domain.com
oAuth redirect url is http://www.domain.com/fb-callback.php
Sammy....?

@falkonpunch

This comment has been minimized.

Show comment
Hide comment
@falkonpunch

falkonpunch Aug 29, 2015

Lol I had this same problem, what I did was remove this piece of code just to see what happens:

// When validation fails or other local issues
echo 'Facebook SDK returned an error: ' . $e->getMessage();
exit;

Run the code. Now it works.

Put that piece back again, run the code.

Still works, wtf?

falkonpunch commented Aug 29, 2015

Lol I had this same problem, what I did was remove this piece of code just to see what happens:

// When validation fails or other local issues
echo 'Facebook SDK returned an error: ' . $e->getMessage();
exit;

Run the code. Now it works.

Put that piece back again, run the code.

Still works, wtf?

@felipemarques

This comment has been minimized.

Show comment
Hide comment
@felipemarques

felipemarques Sep 30, 2015

I had this same problem, anyone can help us ?

felipemarques commented Sep 30, 2015

I had this same problem, anyone can help us ?

@roopam-olx

This comment has been minimized.

Show comment
Hide comment
@roopam-olx

roopam-olx Nov 23, 2015

For anyone else running into this, just make sure you have started a session using session_start() at the beginning of both the scripts.

roopam-olx commented Nov 23, 2015

For anyone else running into this, just make sure you have started a session using session_start() at the beginning of both the scripts.

@BetterWorldCompany

This comment has been minimized.

Show comment
Hide comment
@BetterWorldCompany

BetterWorldCompany Nov 25, 2015

session_start() at the beginning of both the scripts.

It works for me now! Thanks, @roopam-olx

BetterWorldCompany commented Nov 25, 2015

session_start() at the beginning of both the scripts.

It works for me now! Thanks, @roopam-olx

@xero88

This comment has been minimized.

Show comment
Hide comment
@xero88

xero88 Dec 3, 2015

up. help =(((

xero88 commented Dec 3, 2015

up. help =(((

@souchprod

This comment has been minimized.

Show comment
Hide comment
@souchprod

souchprod Jan 3, 2016

Hi,

You receive this error if you origin hostname is different than the target hostname once authenticated.

$loginUrl = $helper->getLoginUrl('http://MyWebSite', $permissions);

with this statement, if the visitor on your website used http://www.mywebsite.com/ the cross-site error will be raised.

You must ensure that origin and target hostname are exactly the same, including the eventual www prefix.

Fixed version:

$loginUrl = $helper->getLoginUrl('http://'.$_SERVER['SERVER_NAME'], $permissions);

souchprod commented Jan 3, 2016

Hi,

You receive this error if you origin hostname is different than the target hostname once authenticated.

$loginUrl = $helper->getLoginUrl('http://MyWebSite', $permissions);

with this statement, if the visitor on your website used http://www.mywebsite.com/ the cross-site error will be raised.

You must ensure that origin and target hostname are exactly the same, including the eventual www prefix.

Fixed version:

$loginUrl = $helper->getLoginUrl('http://'.$_SERVER['SERVER_NAME'], $permissions);
@raper1092

This comment has been minimized.

Show comment
Hide comment
@raper1092

raper1092 Jan 4, 2016

Hi , I have a problem ...
I use https://github.com/darkwhispering/facebook-sdk-v4-codeigniter/tree/fb-sdk-v5-develop and unfortunately only works in one web browser Mozilla Firefox. I do not know whether it is a matter of some saved session / cache but I cleaned everything in the browser.
When I use a browser other than Firefox Login to fail in
logs get this information :
[FACEBOOK PHP SDK] code: 0 | message: Cross-site request forgery validation failed. The "state" param from the URL and session do not match.

Help Please

raper1092 commented Jan 4, 2016

Hi , I have a problem ...
I use https://github.com/darkwhispering/facebook-sdk-v4-codeigniter/tree/fb-sdk-v5-develop and unfortunately only works in one web browser Mozilla Firefox. I do not know whether it is a matter of some saved session / cache but I cleaned everything in the browser.
When I use a browser other than Firefox Login to fail in
logs get this information :
[FACEBOOK PHP SDK] code: 0 | message: Cross-site request forgery validation failed. The "state" param from the URL and session do not match.

Help Please

@chaochen83

This comment has been minimized.

Show comment
Hide comment
@chaochen83

chaochen83 Jan 22, 2016

As I answered here : http://stackoverflow.com/questions/31520593/facebook-php-sdk-5-api-2-4-cross-site-request-forgery-validation-failed-r/34941691#34941691

The Facebook\Facebook object has an instance variable called persistentDataHandler, usually an instance of Facebook\PersistentData\FacebookSessionPersistentDataHandler, which has a set() and a get() method to access the native PHP sessions.

When generating the callback url using:

$loginUrl = $helper->getLoginUrl($callback_url, $permissions);

, the Facebook\Helpers\FacebookRedirectLoginHelper class's getLoginUrl() method will create a 32-character random string, add it to the $loginUrl and save it to $_SESSION['FBRLH_' . 'state'] using persistentDataHandler's set() method.

Later when the $helper->getAccessToken(); is called, the state param in the url will be compared to the stored $_SESSION['FBRLH_' . 'state'] to prevent CSRF. If not match, a FacebookSDKException('Cross-site request forgery validation failed. Required param "state" missing.') will be thrown.

All these being said, you need to make sure your native PHP session feature is properly set during this process. You can check it, by adding die($_SESSION['FBRLH_' . 'state']); after $loginUrl = $helper->getLoginUrl($callback_url, $permissions);, and before $accessToken = $helper->getAccessToken();, to see if that 32-character string is there.

Hope it helps!

chaochen83 commented Jan 22, 2016

As I answered here : http://stackoverflow.com/questions/31520593/facebook-php-sdk-5-api-2-4-cross-site-request-forgery-validation-failed-r/34941691#34941691

The Facebook\Facebook object has an instance variable called persistentDataHandler, usually an instance of Facebook\PersistentData\FacebookSessionPersistentDataHandler, which has a set() and a get() method to access the native PHP sessions.

When generating the callback url using:

$loginUrl = $helper->getLoginUrl($callback_url, $permissions);

, the Facebook\Helpers\FacebookRedirectLoginHelper class's getLoginUrl() method will create a 32-character random string, add it to the $loginUrl and save it to $_SESSION['FBRLH_' . 'state'] using persistentDataHandler's set() method.

Later when the $helper->getAccessToken(); is called, the state param in the url will be compared to the stored $_SESSION['FBRLH_' . 'state'] to prevent CSRF. If not match, a FacebookSDKException('Cross-site request forgery validation failed. Required param "state" missing.') will be thrown.

All these being said, you need to make sure your native PHP session feature is properly set during this process. You can check it, by adding die($_SESSION['FBRLH_' . 'state']); after $loginUrl = $helper->getLoginUrl($callback_url, $permissions);, and before $accessToken = $helper->getAccessToken();, to see if that 32-character string is there.

Hope it helps!

@avastamin

This comment has been minimized.

Show comment
Hide comment
@avastamin

avastamin Feb 8, 2016

session_start() at the beginning of both the scripts worked for me. Thanks @roopam-olx and @BetterWorldCompany

avastamin commented Feb 8, 2016

session_start() at the beginning of both the scripts worked for me. Thanks @roopam-olx and @BetterWorldCompany

@ProdigyView

This comment has been minimized.

Show comment
Hide comment
@ProdigyView

ProdigyView Feb 16, 2016

@chaochen83, what if you are load balancing and there is a different $_SESSION on every server? How can this work with that kind of setup?

ProdigyView commented Feb 16, 2016

@chaochen83, what if you are load balancing and there is a different $_SESSION on every server? How can this work with that kind of setup?

@ProdigyView

This comment has been minimized.

Show comment
Hide comment
@ProdigyView

ProdigyView Feb 16, 2016

I fixed the problem by modifying the FacebookSessionPersistentDataHandler.php and implementing my session storage handler.

ProdigyView commented Feb 16, 2016

I fixed the problem by modifying the FacebookSessionPersistentDataHandler.php and implementing my session storage handler.

@tharindu-b

This comment has been minimized.

Show comment
Hide comment
@tharindu-b

tharindu-b Mar 24, 2016

I had the same problem and it was the session was not started at the beginning of both script files. at lease session has to be start before any of the script files are being executed.

try to validate session with if (session_status() == PHP_SESSION_NONE) { session_start(); }

tharindu-b commented Mar 24, 2016

I had the same problem and it was the session was not started at the beginning of both script files. at lease session has to be start before any of the script files are being executed.

try to validate session with if (session_status() == PHP_SESSION_NONE) { session_start(); }

@nanangkoesharwanto

This comment has been minimized.

Show comment
Hide comment
@nanangkoesharwanto

nanangkoesharwanto Apr 18, 2016

@SammyK , I am so sorry for changing your script, but what I did, make this error gone.
in vendor\facebook\php-sdk-v4\src\Facebook\Helpers\FacebookRedirectLoginHelper.php on line 123, I change this script:

private function makeUrl($redirectUrl, array $scope, array $params = [], $separator = '&')
{
    $state = $this->pseudoRandomStringGenerator->getPseudoRandomString(static::CSRF_LENGTH);
    $this->persistentDataHandler->set('state', $state);

    return $this->oAuth2Client->getAuthorizationUrl($redirectUrl, $state, $scope, $params, $separator);
}

into (I add Session::put('state', $state);)

private function makeUrl($redirectUrl, array $scope, array $params = [], $separator = '&')
{
    $state = $this->pseudoRandomStringGenerator->getPseudoRandomString(static::CSRF_LENGTH);
    $this->persistentDataHandler->set('state', $state);
    Session::put('state', $state);
    return $this->oAuth2Client->getAuthorizationUrl($redirectUrl, $state, $scope, $params, $separator);
}

and on line 234, I change this script:

protected function validateCsrf()
{
    $state = $this->getState();
    $savedState = $this->persistentDataHandler->get('state');

    if (!$state || !$savedState) {
        throw new FacebookSDKException('Cross-site request forgery validation failed. Required param "state" missing.');
    }

    $savedLen = strlen($savedState);
    $givenLen = strlen($state);

    if ($savedLen !== $givenLen) {
        throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
    }

    $result = 0;
    for ($i = 0; $i < $savedLen; $i++) {
        $result |= ord($state[$i]) ^ ord($savedState[$i]);
    }

    if ($result !== 0) {
        throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
    }
}

into (I added $this->persistentDataHandler->set('state', Session::get('state'));)

protected function validateCsrf()
{
    $state = $this->getState();
    $this->persistentDataHandler->set('state', Session::get('state'));
    $savedState = $this->persistentDataHandler->get('state');

    if (!$state || !$savedState) {
        throw new FacebookSDKException('Cross-site request forgery validation failed. Required param "state" missing.');
    }

    $savedLen = strlen($savedState);
    $givenLen = strlen($state);

    if ($savedLen !== $givenLen) {
        throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
    }

    $result = 0;
    for ($i = 0; $i < $savedLen; $i++) {
        $result |= ord($state[$i]) ^ ord($savedState[$i]);
    }

    if ($result !== 0) {
        throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
    }
}

that is all what I did. and the error gone.

nanangkoesharwanto commented Apr 18, 2016

@SammyK , I am so sorry for changing your script, but what I did, make this error gone.
in vendor\facebook\php-sdk-v4\src\Facebook\Helpers\FacebookRedirectLoginHelper.php on line 123, I change this script:

private function makeUrl($redirectUrl, array $scope, array $params = [], $separator = '&')
{
    $state = $this->pseudoRandomStringGenerator->getPseudoRandomString(static::CSRF_LENGTH);
    $this->persistentDataHandler->set('state', $state);

    return $this->oAuth2Client->getAuthorizationUrl($redirectUrl, $state, $scope, $params, $separator);
}

into (I add Session::put('state', $state);)

private function makeUrl($redirectUrl, array $scope, array $params = [], $separator = '&')
{
    $state = $this->pseudoRandomStringGenerator->getPseudoRandomString(static::CSRF_LENGTH);
    $this->persistentDataHandler->set('state', $state);
    Session::put('state', $state);
    return $this->oAuth2Client->getAuthorizationUrl($redirectUrl, $state, $scope, $params, $separator);
}

and on line 234, I change this script:

protected function validateCsrf()
{
    $state = $this->getState();
    $savedState = $this->persistentDataHandler->get('state');

    if (!$state || !$savedState) {
        throw new FacebookSDKException('Cross-site request forgery validation failed. Required param "state" missing.');
    }

    $savedLen = strlen($savedState);
    $givenLen = strlen($state);

    if ($savedLen !== $givenLen) {
        throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
    }

    $result = 0;
    for ($i = 0; $i < $savedLen; $i++) {
        $result |= ord($state[$i]) ^ ord($savedState[$i]);
    }

    if ($result !== 0) {
        throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
    }
}

into (I added $this->persistentDataHandler->set('state', Session::get('state'));)

protected function validateCsrf()
{
    $state = $this->getState();
    $this->persistentDataHandler->set('state', Session::get('state'));
    $savedState = $this->persistentDataHandler->get('state');

    if (!$state || !$savedState) {
        throw new FacebookSDKException('Cross-site request forgery validation failed. Required param "state" missing.');
    }

    $savedLen = strlen($savedState);
    $givenLen = strlen($state);

    if ($savedLen !== $givenLen) {
        throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
    }

    $result = 0;
    for ($i = 0; $i < $savedLen; $i++) {
        $result |= ord($state[$i]) ^ ord($savedState[$i]);
    }

    if ($result !== 0) {
        throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
    }
}

that is all what I did. and the error gone.

@willbchance

This comment has been minimized.

Show comment
Hide comment
@willbchance

willbchance Apr 26, 2016

If you don't give a shit about cross site forgery, go into vendor\facebook\php-sdk-v4\src\Facebook\Helpers\FacebookRedirectLoginHelper.php and delete everything related to the validateCsrf() function.

This will save you a lot of time if the application you're working on is not all that serious.

willbchance commented Apr 26, 2016

If you don't give a shit about cross site forgery, go into vendor\facebook\php-sdk-v4\src\Facebook\Helpers\FacebookRedirectLoginHelper.php and delete everything related to the validateCsrf() function.

This will save you a lot of time if the application you're working on is not all that serious.

@zratan

This comment has been minimized.

Show comment
Hide comment
@zratan

zratan Jun 8, 2016

insert this code after $helper = $fb->getRedirectLoginHelper();

$_SESSION['FBRLH_state']=$_GET['state'];
and it wil work or for more detail visit facebook login apps

zratan commented Jun 8, 2016

insert this code after $helper = $fb->getRedirectLoginHelper();

$_SESSION['FBRLH_state']=$_GET['state'];
and it wil work or for more detail visit facebook login apps

@ninja4web

This comment has been minimized.

Show comment
Hide comment
@ninja4web

ninja4web Jun 25, 2016

For me this was happening due to 'persistent_data_handler' . By adding this in Facebook config, I was able to make it work.

session_start();
$fb = new Facebook\Facebook([
  'app_id'     => '6XXXXXXXXX',
  'app_secret' => '5XXXXXXXXXXXXXX',
  'default_graph_version' => 'v2.6', 
  'persistent_data_handler' => 'session'
  ]);

ninja4web commented Jun 25, 2016

For me this was happening due to 'persistent_data_handler' . By adding this in Facebook config, I was able to make it work.

session_start();
$fb = new Facebook\Facebook([
  'app_id'     => '6XXXXXXXXX',
  'app_secret' => '5XXXXXXXXXXXXXX',
  'default_graph_version' => 'v2.6', 
  'persistent_data_handler' => 'session'
  ]);

@rainbowhat

This comment has been minimized.

Show comment
Hide comment
@rainbowhat

rainbowhat Jul 23, 2016

I disabled CSRF for getAccessToken :\ What's the worse that can happen?

rainbowhat commented Jul 23, 2016

I disabled CSRF for getAccessToken :\ What's the worse that can happen?

@nidhigill

This comment has been minimized.

Show comment
Hide comment
@nidhigill

nidhigill Jul 26, 2016

when i run "login with facebook locally it runs properly but when i upload it on server it shows me an error Facebook SDK returned an error: Cross-site request forgery validation failed. The "state" param from the URL and session do not match.

following is the login callback.php

'xxxxxxxxx', 'app_secret' => 'xxxxxxxxx', 'default_graph_version' => 'v2.5', ]); $helper = $fb->getRedirectLoginHelper(); try { $accessToken = $helper->getAccessToken(); } catch(Facebook\Exceptions\FacebookResponseException $e) { echo 'Graph returned an error: ' . $e->getMessage(); exit; } catch(Facebook\Exceptions\FacebookSDKException $e) { echo 'Facebook SDK returned an error: ' . $e->getMessage(); exit; } if (isset($accessToken)) { // Logged in! try { // Returns a `Facebook\FacebookResponse` object $response = $fb->get('/me?fields=id,name,first_name,last_name,email,gender,locale,picture',$accessToken); } catch(Facebook\Exceptions\FacebookResponseException $e) { echo 'Graph returned an error: ' . $e->getMessage(); exit; } catch(Facebook\Exceptions\FacebookSDKException $e) { echo 'Facebook SDK returned an error: ' . $e->getMessage(); exit; } $user_profile = $response->getGraphUser(); //print_r($user_profile);die; $user = new Users(); //db class $user_data = $user->checkUser($user_profile['first_name'],$user_profile['last_name'],$user_profile['email'],$user_profile['password'],$user_profile['gender']); ``` if(!empty($user_data)){ //die('ss'); //echo"
";print_r($user_data);die;
    $output = '

Facebook Profile Details

'; $output .= '
Name : ' . $user_data['name'].' '.$user_data['surname']; $output .= '
Email : ' . $user_data['emailorphone']; $output .= '
Email : ' . $user_data['password']; $output .= '
Email : ' . $user_data['gender']; $output .= '
You are login with : Facebook'; $output .= '
Logout from Facebook'; }else{ $output = '

Some problem occurred, please try again.

'; } ``` echo $output; //$_SESSION['facebook_access_token'] = (string) $accessToken; // Now you can redirect to another page and use the // access token from $_SESSION['facebook_access_token'] }

nidhigill commented Jul 26, 2016

when i run "login with facebook locally it runs properly but when i upload it on server it shows me an error Facebook SDK returned an error: Cross-site request forgery validation failed. The "state" param from the URL and session do not match.

following is the login callback.php

'xxxxxxxxx', 'app_secret' => 'xxxxxxxxx', 'default_graph_version' => 'v2.5', ]); $helper = $fb->getRedirectLoginHelper(); try { $accessToken = $helper->getAccessToken(); } catch(Facebook\Exceptions\FacebookResponseException $e) { echo 'Graph returned an error: ' . $e->getMessage(); exit; } catch(Facebook\Exceptions\FacebookSDKException $e) { echo 'Facebook SDK returned an error: ' . $e->getMessage(); exit; } if (isset($accessToken)) { // Logged in! try { // Returns a `Facebook\FacebookResponse` object $response = $fb->get('/me?fields=id,name,first_name,last_name,email,gender,locale,picture',$accessToken); } catch(Facebook\Exceptions\FacebookResponseException $e) { echo 'Graph returned an error: ' . $e->getMessage(); exit; } catch(Facebook\Exceptions\FacebookSDKException $e) { echo 'Facebook SDK returned an error: ' . $e->getMessage(); exit; } $user_profile = $response->getGraphUser(); //print_r($user_profile);die; $user = new Users(); //db class $user_data = $user->checkUser($user_profile['first_name'],$user_profile['last_name'],$user_profile['email'],$user_profile['password'],$user_profile['gender']); ``` if(!empty($user_data)){ //die('ss'); //echo"
";print_r($user_data);die;
    $output = '

Facebook Profile Details

'; $output .= '
Name : ' . $user_data['name'].' '.$user_data['surname']; $output .= '
Email : ' . $user_data['emailorphone']; $output .= '
Email : ' . $user_data['password']; $output .= '
Email : ' . $user_data['gender']; $output .= '
You are login with : Facebook'; $output .= '
Logout from Facebook'; }else{ $output = '

Some problem occurred, please try again.

'; } ``` echo $output; //$_SESSION['facebook_access_token'] = (string) $accessToken; // Now you can redirect to another page and use the // access token from $_SESSION['facebook_access_token'] }
@SJ04

This comment has been minimized.

Show comment
Hide comment
@SJ04

SJ04 Sep 4, 2017

Hello Guys,

Can I also please have any Help with my Issue.

I am having issue while copyright the video,.

#848

i will be really helpful if i can receive any help.

thank you

SJ04 commented Sep 4, 2017

Hello Guys,

Can I also please have any Help with my Issue.

I am having issue while copyright the video,.

#848

i will be really helpful if i can receive any help.

thank you

@larssn

This comment has been minimized.

Show comment
Hide comment
@larssn

larssn Mar 27, 2018

If you use AWS' ELB do this:

require 'path/to/facebook/autoload.php';
$fb = new Facebook\Facebook([
  'app_id'     => 'XXXXXXXXX',
  'app_secret' => 'XXXXXXXXXXXXXX',
  'default_graph_version' => 'v2.10', 
  'persistent_data_handler' => new CookieSessionHandler()
  ]);

class CookieSessionHandler() implements Facebook\PersistentData\PersistentDataInterface {
   function get($key) {
      return $_COOKIE[$key];
   }

   function set($key, $value) {
      setcookie($key, $value);
   }
}

This will switch to cookies (which the ELB supports).

larssn commented Mar 27, 2018

If you use AWS' ELB do this:

require 'path/to/facebook/autoload.php';
$fb = new Facebook\Facebook([
  'app_id'     => 'XXXXXXXXX',
  'app_secret' => 'XXXXXXXXXXXXXX',
  'default_graph_version' => 'v2.10', 
  'persistent_data_handler' => new CookieSessionHandler()
  ]);

class CookieSessionHandler() implements Facebook\PersistentData\PersistentDataInterface {
   function get($key) {
      return $_COOKIE[$key];
   }

   function set($key, $value) {
      setcookie($key, $value);
   }
}

This will switch to cookies (which the ELB supports).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment