Menu

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

closed
nobody
None
2016-06-25
2015-07-21
Anonymous
No

Originally created by: tatters1979

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.');
    }
}

Discussion

1 2 > >> (Page 1 of 2)
  • Anonymous

    Anonymous - 2015-07-21

    Originally posted by: SammyK

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

     
  • Anonymous

    Anonymous - 2015-07-21

    Originally posted by: tatters1979

    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');
    
     
  • Anonymous

    Anonymous - 2015-07-21

    Originally posted by: SammyK

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

    var_dump($helper->getError());
    
     
  • Anonymous

    Anonymous - 2015-07-21

    Originally posted by: tatters1979

    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;
    }
    
     
  • Anonymous

    Anonymous - 2015-07-22

    Originally posted by: SammyK

    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?

     
  • Anonymous

    Anonymous - 2015-07-22

    Originally posted by: tatters1979

    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

     
  • Anonymous

    Anonymous - 2015-07-22

    Originally posted by: SammyK

    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.

     
  • Anonymous

    Anonymous - 2015-07-22

    Originally posted by: tatters1979

    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.

     
  • Anonymous

    Anonymous - 2015-07-22

    Originally posted by: SammyK

    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);
    
     
  • Anonymous

    Anonymous - 2015-07-22

    Originally posted by: tatters1979

    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?

     
  • Anonymous

    Anonymous - 2015-07-22

    Originally posted by: SammyK

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

     

    Related

    Tickets: #470

  • Anonymous

    Anonymous - 2015-07-22

    Originally posted by: tatters1979

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

     
  • Anonymous

    Anonymous - 2015-07-22

    Originally posted by: SammyK

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

     
  • Anonymous

    Anonymous - 2015-07-22

    Originally posted by: tatters1979

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

     
  • Anonymous

    Anonymous - 2015-07-22

    Originally posted by: SammyK

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

     
  • Anonymous

    Anonymous - 2015-07-25

    Originally posted by: eduardomazolini

    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();

     
  • Anonymous

    Anonymous - 2015-07-27

    Originally posted by: tatters1979

    @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.

     
  • Anonymous

    Anonymous - 2015-07-27

    Originally posted by: tatters1979

    @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.

     
  • Anonymous

    Anonymous - 2015-07-27

    Originally posted by: SammyK

    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. :)

     
  • Anonymous

    Anonymous - 2015-07-27

    Originally posted by: tatters1979

    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;
    
     
  • Anonymous

    Anonymous - 2015-07-27

    Originally posted by: SammyK

    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();
    
     
  • Anonymous

    Anonymous - 2015-07-27

    Originally posted by: tatters1979

    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());
    }
    
     
  • Anonymous

    Anonymous - 2015-07-27

    Originally posted by: SammyK

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

     
  • Anonymous

    Anonymous - 2015-07-27

    Originally posted by: tatters1979

    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 :)

     
  • Anonymous

    Anonymous - 2015-07-28

    Originally posted by: tatters1979

    @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

     
1 2 > >> (Page 1 of 2)

Log in to post a comment.

MongoDB Logo MongoDB