
For the last couple of days I have been working with Twitter API, trying to make the api usable for flash in browser the same way as FacebookLogger (Facebook API extension) is. Guess what, I did it! I created TwitterLogger. TwitterLogger class extends official TwitterScript (ActionScript API) and implements OAuth (and TwitterOAuth – PHP Library to support OAuth for Twitter’s REST API) authorization protocol to gain full access into Twitter API from flash in browser.
TwitterScript already contains full api access but some call requires authorization that brings you into 2 issues:
- obtain username and password from user – unwanted operation
- crossdomain authorization – only possible for AIR due to Twitter crossdomain policy restriction
Sets the username and password for this instance, setting the flag to use https to true. Note that this will not work at all in Flash player 9.0.115, and will only work in later versions if the remote server has the <code>allow-http-request-headers-from</code> tag set permissively in its crossdomain policy file. For more information see: http://kb.adobe.com/selfservice/viewContent.do?externalId=kb403184. Unfortunately Twitter has it set to (as of Sept 2008): <allow-http-request-headers-from domain=”*.twitter.com” headers=”*” secure=”true”/> which only lets in the twitter badges originating from twitter.com. Since that’s the case, authentication will only work for AIR.
If you use this for Flash in the browser, it will fail over to the browser’s basic auth without an issue. (described in com.twitter.api.Twitter.setAuthenticationCredentials())
This requires another method on scene. Since Twitter introduced OAuth it is possible to get connection into Twitter API via this open source secure authorization. To communicate with Twitter we gonna use server side proxy. So lets start:
1. Register a new twitter application, these settings are crucial:
Application Website: http://blog.yoz.sk/examples/twitterLogger/
Application Type: Browser
Callback URL: http://blog.yoz.sk/examples/twitterLogger/callback.php
Default Access type: Read & Write
Use Twitter for login: Yes
2. download OAuth.php and twitteroauth.php from TwitterOAuth into /library/ dir
3. create /config.php file containing:
<?php
// fill your own Twitter application Consumer key
define('CONSUMER_KEY', 'qSoF24kOuNCiPCQwWfe0yQ');
// fill your own Twitter application Consumer secret
define('CONSUMER_SECRET', 'xahJ7hpJeevq411N5NQXcTbJ5hQFWDwidtTpsbc');
// fill your Twitter application Callback URL
define('OAUTH_CALLBACK', 'http://blog.yoz.sk/examples/twitterLogger/callback.php');
4. /connect.php file:
<?php
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0");
header("Pragma: no-cache");
header("Last-Modified:".gmdate("D, d M Y H:i:s")." GMT");
header('Content-Type: text/html; charset=utf-8');
session_start();
require_once 'config.php';
require_once 'library/twitteroauth.php';
$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET);
$request_token = $connection->getRequestToken(OAUTH_CALLBACK);
$_SESSION['oauth_token'] = $token = $request_token['oauth_token'];
$_SESSION['oauth_token_secret'] = $request_token['oauth_token_secret'];
$url = $connection->getAuthorizeURL($token);
header('Location: ' . $url);
exit;
5. /callback.php
<?php
session_start();
require_once 'config.php';
require_once 'library/twitteroauth.php';
$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $_SESSION['oauth_token'], $_SESSION['oauth_token_secret']);
$access_token = $connection->getAccessToken($_REQUEST['oauth_verifier']);
$_SESSION['access_token'] = $access_token;
unset($_SESSION['oauth_token']);
unset($_SESSION['oauth_token_secret']);
?>
<!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" xml:lang="sk" lang="sk" dir="ltr">
<head>
<script type="text/javascript">
<!--
if(window.opener && window.opener.confirmTwitterConnection)
{
window.opener.confirmTwitterConnection();
self.close();
}
//-->
</script>
</head>
<body>
<p>You may now close this window.</p>
</body>
</html>
6. /proxy.php
<?php
session_start();
require_once 'config.php';
require_once 'library/twitteroauth.php';
$access_token = $_SESSION['access_token'];
$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $access_token['oauth_token'], $access_token['oauth_token_secret']);
$parameters = array();
foreach($_POST as $key => $value)
if($key != "method" && $key != "url")
$parameters[$key] = $value;
echo $connection->OAuthRequest($_POST['url'], $_POST['method'], $parameters);
7. Create new flex project
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
applicationComplete="init()">
<mx:Script>
<![CDATA[
import sk.yoz.events.TwitterLoggerEvent;
import sk.yoz.net.TwitterLogger;
private var connector:String = "http://blog.yoz.sk/examples/twitterLogger/connect.php";
private var proxy:String = "http://blog.yoz.sk/examples/twitterLogger/proxy.php";
[Bindable]
private var twitter:TwitterLogger = new TwitterLogger(connector, proxy);
[Bindable]
private var lastCallResult:String = "";
private function init():void
{
twitter.addEventListener(TwitterLoggerEvent.CALL_COMPLETE, callComplete);
}
private function callComplete(event:TwitterLoggerEvent):void
{
lastCallResult = event.data.toString();
}
]]>
</mx:Script>
<mx:HBox>
<mx:Button label="connect" click="twitter.connect()" />
<mx:Label text="{twitter.connected ? 'connected' : 'not connected'}" />
</mx:HBox>
<mx:HBox>
<mx:TextInput id="status" text="hallo world status"/>
<mx:Button click="twitter.setStatus(status.text)" label="update status"/>
</mx:HBox>
<mx:TextArea text="{lastCallResult}" width="100%" height="100%"/>
</mx:Application>
8. Download TwitterScript classes and make sure to rewrite private to protected namespace for these methods and vars in com.twitter.api.Twitter class:
protected var loaders;
protected function addLoader(...
protected function errorHandler(...
9. Download sk.yoz.net.TwitterLogger, sk.yoz.net.TwitterProxyLoader and sk.yoz.events.TwitterLoggerEvent classes into your flex project under the correct namespace (sk.yoz…)
10. Make sure your index.html wrapper class defines allowScriptAccess and flash id and name, it may look like something like this:
<!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>TwitterLogger</title>
<script type="text/javascript" src="js/swfobject.js"></script>
<script type="text/javascript">
//<![CDATA[
var flashvars = {}
var params = {
allowScriptAccess: "sameDomain"
};
var attributes = {
id: "sz",
name: "sz"
};
swfobject.embedSWF("App.swf", "alternative", "100%", "100%", "9.0.124",
"expressInstall.swf", flashvars, params, attributes);
//]]>
</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>
Publish html template and copy all flash files into your application website. You should now have this structure in there (http://blog.yoz.sk/examples/twitterLogger/)
/js/swfobject.js
/library/OAuth.php
/library/twitteroauth.php
/App.swf
/callback.php
/config.php
/connect.php
/index.html
/proxy.php
If you do same changes, make sure all these files are on same domain because it uses PHP Session to store token and JavaScript between-window communication. Now lets see our application (http://blog.yoz.sk/examples/twitterLogger/):
To update your satus, first click on connect, window popup opens and redirects itself into Twitter asking for permission. After you click allow in popup, popup closes itself and change status in flex near connect button to “connected”. Now you are ready to update your Twitter status. TextArea contains last Twitter appi call reply (after status update). The good thing with OAuth is, it remembers your acception for some time, so you do not have to click allow every time…
There may occur error on Twitter popup saying:
This page is no longer valid. It looks like someone already used the token information you provided. Please return to the site that sent you to this page and try again … it was probably an honest mistake.
I guess it may have something to do with cached request on connect.php, so I added few expire headers into it.
Where to go from here: