Facebook integration for iFrame Apps: Getting an oauth_token from a signed request using the PHP Facebook API

doubletapeg's Avatar

doubletapeg

21 Sep, 2011 07:51 PM

Hey Roar Gang!

This isn't a request for help. I figured if someone else ended up running into the same problems I've been having trying to integrate my game with Facebook as an iFrame app, they might look here for help. So, I'd like to detail what I ended up doing to get an oauth_token. Not only does this method eliminate unnecessary redirects, as far as I can tell the oauth_token fetched this way seems to work correctly when piped into Roar. I've tried oauth_tokens I extracted from the signed request in the server console with /facebook/create_oauth and /facebook/login_oauth and received "ok" responses from Roar every time! :D

Anyway, my PHP script goes something like this:

<?php
require_once "facebook.php";

//Set Facebook data.
$app_id = "Your appID here";
$app_secret = "Your appSecret here";
$app_FacebookURL = "https://apps.facebook.com/your app's Facebook location here";
$permissions = "Permissions you want here";

//Begin facebook session.
$facebook = new Facebook( array( 'appId' => $app_id, 'secret' => $app_secret) ); 

//Fetch the signed request.
$signedRequest = $facebook->getSignedRequest();

//Check for oauth_token in signed request.
if (!array_key_exists('oauth_token', $signedRequest))
{
    //There is no oauth_token in the signed request so forward to authorizing page.
    echo "<script>top.location.href='https://graph.facebook.com/oauth/authorize?client_id=" . $app_id . "&redirect_uri=" . urlencode($app_FacebookURL)  . "&scope=$permissions'</script>";
}
else //if (array_key_exists('oauth_token', $signedRequest))
{
    //There is an oauth_token in the signed request.  For now just print it...
    echo("oauth_token is: ");
    echo($signedRequest['oauth_token']);

    //... and also use it to fetch the user's name then print the user's name so I know it's working.
    $graph_url = "https://graph.facebook.com/me?access_token=" . $signedRequest['oauth_token'];
    $user = json_decode(file_get_contents($graph_url));
    echo("\nHello " . $user->name . "!");
}
?>

I hope that helps somebody. Sure would've saved me several days worth of aggravation if something like this was available right from the get go. :p

  1. Support Staff 1 Posted by Clint Walker on 23 Sep, 2011 05:17 PM

    Clint Walker's Avatar

    Awesome thanks for that :)
    Would you mind if we put a copy of this up on our official docs, it'd be super helpful for other PHP devs!

  2. 2 Posted by doubletapeg on 24 Sep, 2011 07:41 AM

    doubletapeg's Avatar

    No, I don't mind at all. Feel free to add it to the official docs. If it saves somebody any time at all it'll make me real happy! Of course a short credit mentioning that I submitted it would definitely make me happy too. hehe~ ;D

    Thanks again!

  3. 3 Posted by Mike Anderson on 26 Sep, 2011 06:10 AM

    Mike Anderson's Avatar

    It's worth noting that if you have a signed request you can use an alternative login/create methods (which have lower latency than the oauth forms). These are the facebook/login_signed and facebook/create_signed methods.

    Regards,
    Mike

  4. 4 Posted by doubletapeg on 26 Sep, 2011 08:21 AM

    doubletapeg's Avatar

    Thanks for the reminder Mike!

    Yes, I am aware of facebook/login_signed and create_signed. Actually, I was able to get my game to sign into Roar with signed requests rather quickly. But, I ended up going back to figuring out the oauth way because, as far as I can tell, Facebook's graph API seems to require the actual oauth_token string and not the signed request string for many of its functions.

    So, I figured I needed to get the oauth_token from somewhere and that's when I found out after forcing myself to read through facebook.php that a signed request is not just a random string to be used as a key but something which is parseable. Further more, I also learned that an oauth_token is embedded inside the signed request under the right circumstances. The following is the parts of facebook.php which pertains to this issue.

    /**
    * Get the data from a signed_request token.
    *
    * @return string The base domain
    */
    public function getSignedRequest() {
    if (!$this->signedRequest) {
      if (isset($_REQUEST['signed_request'])) {
        $this->signedRequest = $this->parseSignedRequest(
          $_REQUEST['signed_request']);
      }
    }
    return $this->signedRequest;
    }
    
     /**
       * Parses a signed_request and validates the signature.
       *
       * @param string $signed_request A signed token
       * @return array The payload inside it or null if the sig is wrong
       */
    protected function parseSignedRequest($signed_request) {
    list($encoded_sig, $payload) = explode('.', $signed_request, 2);
    
    // decode the data
    $sig = self::base64UrlDecode($encoded_sig);
    $data = json_decode(self::base64UrlDecode($payload), true);
    
    if (strtoupper($data['algorithm']) !== 'HMAC-SHA256') {
      self::errorLog('Unknown algorithm. Expected HMAC-SHA256');
      return null;
    }
    
    // check sig
    $expected_sig = hash_hmac('sha256', $payload,
                              $this->getApiSecret(), $raw = true);
    if ($sig !== $expected_sig) {
      self::errorLog('Bad Signed JSON signature!');
      return null;
    }
    
    return $data;
    }
    

    Now, the code in parseSignedRequest() went right over my head but I was luckily able to see the output I piped out into a webpage from $facebook->getSignedRequest(). I saw that indeed the signed request was parsed and broken down into its component parts after it came back from parseSignedRequest(). I didn't see an oauth_token at first though. That only happened after I had authorized the app through facebook by first redirecting through https://graph.facebook.com/oauth/authorize. That reminds me...

    There was some thread in the boards here about someone getting a "Bad Signed JSON signature!" error. Well, that error as you can see in the code above is in parseSignedRequest() and that is the only place it appears in facebook.php. It may be that "Bad Signed JSON signature!" gets thrown if the oauth_token portion of the signed request is missing. From what I can tell, it's apparently possible to have a "valid" signed request that does not have the oauth_token in it. I guess you can be validly signed into Facebook but if you don't currently have any apps authorized because the token expired then you don't get one in the signed request or something like that I think. Ugh... It's all so confusing but either way I'm glad that what I was able to figure out works for me. :p

  5. 5 Posted by Mike Anderson on 26 Sep, 2011 09:08 AM

    Mike Anderson's Avatar

    I have a feeling that the missing oauth_token can happen if the user declines to grant your app permissions. At least I seem to recall something like that.

  6. 6 Posted by doubletapeg on 26 Sep, 2011 04:33 PM

    doubletapeg's Avatar

    I think you're right Mike. If a user declines to grant app permission then they are probably being redirected to the redirect_uri that was submitted to the graph API without the oauth_token in the signed request.

  7. Clint Walker closed this discussion on 07 Oct, 2011 06:08 AM.

Comments are currently closed for this discussion. You can start a new one.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac

Recent Discussions

17 Oct, 2014 06:28 AM
05 Oct, 2014 04:25 PM
02 Oct, 2014 09:48 PM
06 Aug, 2014 05:05 AM
09 Jul, 2014 10:45 AM

 

09 Jul, 2014 09:46 AM
01 Jul, 2014 01:37 AM
16 Jun, 2014 03:00 PM
13 Jun, 2014 06:11 AM
18 May, 2014 09:21 PM
16 May, 2014 02:22 PM