Authorizing Iframe Facebook Applications For Graph API

This article continues my exploration of best facebook graph api integration into your flash app. Before continue reading, make sure you understand the previous article. Due to huge interest, I am adding codes that makes your flash app working with graph api within facebook iframe. Try this app live on http://apps.facebook.com/blogoauthgraph/, notice once you get there, you are redirected to grant permissions (if not authorized or granted already) and then redirected back to the app, where you are connected and ready to use graph api.

What I did was changing one line of ActionScript, I added autoConnect() methods that sends app flashvars directly into FacebookOAuthGraph object.

var facebook:FacebookOAuthGraph = new FacebookOAuthGraph();
...
facebook.autoConnect(parameters); // passing flashvars

See full ActionScript code for details.

Now there is a different html wrapper for facebook iframe – facebook.php:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" lang="cs" xml:lang="cs"> 
<head> 
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <meta http-equiv="Content-language" content="cs" />
    <title>FacebookOAuthGraphTest</title>
    <script type="text/javascript" src="js/swfobject.js"></script>
    <script type="text/javascript">
        //<![CDATA[
		function allRequestParameters()
		{
			var data = {};
			var strHref = window.location.href;
			if ( strHref.indexOf("?") > -1 ) {
				var strQueryString = strHref.substr(strHref.indexOf("?")+1);
				var aQueryString = strQueryString.split("&");
				for ( var iParam = 0; iParam < aQueryString.length; iParam++ ) {
					var aParam = aQueryString[iParam].split("=");
					data[aParam[0]] = aParam[1];
				}
			}
			return data;
		}
		
		function generateFlash()
		{
			var flashvars = allRequestParameters();
			flashvars.session = '{"access_token":"' + signed_request.oauth_token + '"}';
			
			var params = {
				allowScriptAccess: "sameDomain"
			};
			
			var attributes = {
				id: "FacebookOAuthGraphTest",
				name: "FacebookOAuthGraphTest"
			};
			
			swfobject.embedSWF("FacebookOAuthGraphTest.swf?v=2", "alternative", "100%", "100%", "10.0.0",
				"expressInstall.swf", flashvars, params, attributes);
		}
		
		<?php
		$signed_request = $_REQUEST["signed_request"];
		list($encoded_sig, $payload) = explode('.', $signed_request, 2); 
		$data = base64_decode(strtr($payload, '-_', '+/'));
		echo "var signed_request=" . $data . ";";
		?>
		
		if(!signed_request.oauth_token){
			window.top.location = "https://www.facebook.com/dialog/oauth"
				+ "?client_id=" + '268718683475'
				+ "&redirect_uri=" + 'http://apps.facebook.com/blogoauthgraph/'
				+ "&scope=publish_stream,user_photos,user_photo_video_tags"
				+ "&response_type=token";
		}else{
			generateFlash();
		}
        //]]>
    </script>
    <style>
        body {margin:0px;overflow:hidden}
        html, body, object, embed {width:100%;height:100%;outline:none;}
    </style>
 </head>
 <body style="text-align:center;">
    <div id="alternative">
        <a href="http://www.adobe.com/go/getflashplayer">
            <img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash player" />
        </a>
    </div>
</body>
</html>

There are few lines of code to be mentioned:

  • getRequestParameter(name) – returns GET parameter from iframe url, you can use your own functions
  • allRequestParameters() – returns object consisting of all iframe GET parameters, used to pass flashvars into our flash
  • php code to define javascript signed_request variable containing valid token
  • window.top.location – if there is no token parameter found (not authorized yet), you are redirected to the facebook authorization. Do not forget to change client_id and redirect_uri when using for your app.

Facebook settings:

App ID: 268718683475
Site URL: http://blog.yoz.sk/examples/FacebookOAuthGraph/
Site Domain: yoz.sk
Canvas Page: http://apps.facebook.com/blogoauthgraph/
Canvas URL: http://blog.yoz.sk/examples/FacebookOAuthGraph/facebook.php?a=b
Canvas FBML/iframe: iframe

Disable Deprecated Auth Methods: Enabled
Stream post URL security: Disabled
OAuth 2.0 for Canvas: Enabled
POST for Canvas: Enabled
Canvas Session Parameter (Deprecated): Disabled
November 2010 Rollup: Enabled
Timezone-less events: Enabled
Upgrade to Requests 2.0: Enabled
JSON Encoding Empty Arrays: Enabled

Here is the final facebook app http://apps.facebook.com/blogoauthgraph/

updated Jul 21, 2010: Quickfix for late facebook changes:

updated Jul 22, 2010: Facebook rollbacked the change and added “Canvas Session Parameter” parameter in facebook app settings / Migrations tab. With this setting enabled, your apps should work normally as they previously did.

updated Mar 16, 2011: Catching token from POST parameter.

115 comments so far

  1. saikumar April 8, 2011 18:40

    please solve issue
    http://www.adobe.com/devnet/facebook/samples.html
    at sample3
    issue:- album length showing 0

  2. saikumar April 8, 2011 18:42

    please let me know how to connect facebook and access its album in flex give me example with source code

  3. Garcimore April 15, 2011 22:59

    I Jozef,

    you will say that I have always problem with Internet Explorer… But when I test http://apps.facebook.com/blogoauthgraph/ on IE, there is a flash error in autoConnect(…) function : “var session:Object = JSON.decode(parameters.session);” doesn’t work ==> it’s impossible to get the value of parameters.session

    Do you have an idea why the flashvar in .js is correctly get in Firefox and Chrome but not with IE ?

    Thanks in advance.
    Garcimore

  4. Garcimore April 16, 2011 21:16

    I Jozef,

    Sorry for my last comment, in fact it’s not a problem of flashvars getting with IE… but a problem of flashvars encoding in the javascript code.
    I suggest that you update your facebook.php :
    – in the generateFlash() function : flashvars.session = encodeURIComponent(‘{“access_token”:”‘ + signed_request.oauth_token + ‘”}’);
    With this change the autoconnect will work with IE, 😉

    Best regards.
    Garcimore.

  5. Jozef Chúťka April 19, 2011 22:10

    thank you for solution Garcimore

  6. William Everich April 21, 2011 23:07

    Right now this is my favorite page on the internet. Thank you all!!

  7. Bill Langley May 3, 2011 18:27

    I can’t get this new auth to work. I don’t understand how I’m supposed to extract the top.location access_token hash when the app is inside an iframe. Also, I tried the PHP $signed_request method and it always comes up empty. I have “Oauth 2 for Canvas” and “POST for Canvas” enabled. No matter what I try, I can’t get to the access_token. What am I missing here?

  8. Jozef Chúťka May 4, 2011 09:51

    hi Bill.
    – you do not extract nothing from top.location, you pass there url to get authorized
    – if you have correct facebook setting (see the ones from me) you should get some authorization info in POST variables. make sure yor server support _POST variable

  9. Bill Langley May 4, 2011 18:42

    Hi Jozef,

    My client’s server accepts _POST vars because when I use FB’s technique:

    <?php

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

    $code = $_REQUEST["code"];

    if(empty($code)) {
    $dialog_url = "http://www.facebook.com/dialog/oauth?client_id=&quot;
    . $app_id . "&redirect_uri=" . urlencode($my_url);

    echo(" top.location.href='” . $dialog_url . “‘”);
    }

    $token_url = “https://graph.facebook.com/oauth/access_token?client_id=”
    . $app_id . “&redirect_uri=” . urlencode($my_url) . “&client_secret=”
    . $app_secret . “&code=” . $code;

    $access_token = file_get_contents($token_url);

    $graph_url = “https://graph.facebook.com/me?” . $access_token;

    $user = json_decode(file_get_contents($graph_url));

    echo(“Hello ” . $user->name);

    ?>

    I am able to get $code, but unable to get file_get_contents($token_url); to work because (I’m assuming) the $token_url is secure.

    However, when I use your technique I am never able to get $signed_request either with $_REQUEST[“signed_request”] or $_POST[“signed_request”]. So, I’m stuck with a looping app.

    Also, I don’t understand how your post “neverending facebook changes…” applies to this. They seem like 2 different techniques.

    I greatly appreciate any light you can shed on this.

    Thx,
    WL

    http://apps.facebook.com/sambazon_warrior_up

  10. Jozef Chúťka May 4, 2011 20:35

    request to http://apps.facebook.com/sambazon_warrior_up :

    POST /fbapp/ HTTP/1.1
    Host: sambazon.com
    Referer: http://apps.facebook.com/sambazon_warrior_up/

    signed_request=N7GgX95r…

    asi you can see, there surely is post parameter available!

  11. Bill Langley May 5, 2011 01:06

    Now I’m even more perplexed. I can now see the signed_request variable and am able to parse the oauth_token out of it, but I’m still seeing the page constantly refresh itself… even if I remove the generateFlash() function. On Chrome it just repeats. On Firefox it throws up “Object Moved”. Here is my PHP:

    BTW: I am not able to create the signed_request var like your example. The initial var signed_request=; throws up an error in my JS console.

  12. Bill Langley May 5, 2011 01:07

    Sorry, guess the PHP got consumed:

    $app_uri = “http://apps.facebook.com/sambazon_warrior_up/”;
    $auth_uri = “https://www.facebook.com/dialog/oauth”;
    $client_id = “[my id]”;
    $scope = “publish_stream,user_photos,user_photo_video_tags”;

    $signed_request = $_POST[“signed_request”];
    list($encoded_sig, $payload) = explode(‘.’, $signed_request, 2);
    $data = base64_decode(strtr($payload, ‘-_’, ‘+/’));

    if(empty($signed_request)){
    echo ( “window.top.location = ‘” . $auth_uri .
    “?client_id=” . $client_id .
    “&redirect_uri=” . urlencode($app_uri) .
    “&scope=” . $scope .
    “&response_type=token’;”);
    }else{
    echo “var signed_request=” . $data . “;”;
    echo “generateFlash();”;
    }

  13. Bill Langley May 5, 2011 20:04

    Yikes! Sorry for all the frustration. The root problem was that I hadn’t included the www in the site’s app url. The client redirects when it is missing. The redirect then caused the POST data to disappear.

    Thanks for all your help!

  14. Etienne June 11, 2011 10:08

    Hi Jozef,

    I discover something strange…
    Concerning as3 graph api iframe embeding exemples from facebook-actionscript-api google code (wich are working fine) :

    On firefox 3.6.12 and previous, the auto init (auto connect) is not working. The app will work outside of FB but not in the canvas.
    But if you set a setTimeout (even with no delay) before the embed swf function….. it works !!

    I know that doesn’t concern your own embeding solution but the facebook-actionscript-api one.

    However, perhaps yours have the same kind of issue on on 3.6.12 and previous.

  15. Jozef Chúťka June 13, 2011 09:56

    hi Etienne,
    glad you made it work. its really interesting that it does not work correctly with ff. it may be due to flash app is not completely prepared. not sure what may case the issue:
    – missing flashvars?
    – shared object not ready?
    – stage and urlloader not ready?

Leave a comment

Please be polite and on topic. Your e-mail will never be published.