TwitterLogger Class To Full Twitter API Access From ActionScript 3

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:

56 comments so far

  1. Klas Lundberg April 14, 2010 02:44

    Exellent work! I like it! =)

  2. Jozef Chúťka April 14, 2010 09:38

    thanks Klas

  3. Dimitree April 20, 2010 10:42

    You have very helpful examples in your blog!

  4. [...] days before while I was working on TwitterLogger Class for ActionScript 3 I discovered OAuth – an open protocol to allow secure API authorization . While reading all [...]

  5. arun June 14, 2010 11:15

    Thanks for this example. Please let me know how to disconnect/logout of twitter from within flex.

  6. Jozef Chúťka June 14, 2010 11:45
  7. Albin June 14, 2010 12:22

    Hi. I get the
    “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.” message from twitter, even with the headers included in the connect.php file. Also, the twitter-connect window that is launched doesn’t seem to have a ?oauth_token=
    value … it’s just blank.. any idea?

  8. Helliax June 23, 2010 22:28

    I’m thinking it’s because there’s some lag loading the keys, so it goes to the twitter authorize page before those variables are loaded. Just a guess.

  9. Helliax July 7, 2010 23:32

    For anyone using this, it seems that the proxy.php example hands your tweet string to twitteroauth with escape slashes. So a tweet of:

    These are “double quotes”

    will show up on Twitter.com as:

    These are \”double quotes\”

    So I just did the following on line 11 of proxy.php

    if($key != “method” && $key != “url”){
    $value = str_replace(“\\\””,”\””,$value);
    $value = str_replace(“\\’”,”‘”,$value);
    $value = str_replace(“\\\\”,”\\”,$value);
    $parameters[$key] = $value;
    }

    I’m sure there’s a better method, but that’s what worked for me.

  10. Jozef Chúťka July 8, 2010 10:16

    @Helliax,
    thnx for noticing. I am few years out of php but if I am correct, this has to do with archaic Magic Quotes
    http://php.net/manual/en/security.magicquotes.php
    you should be able to use stripslashes() http://www.php.net/manual/en/function.stripslashes.php if magic quotes are on http://www.php.net/manual/en/function.get-magic-quotes-gpc.php

  11. Helliax July 14, 2010 17:28

    Thanks for the tip Jozef! I’m not a PHP programmer by any means, so it was a small adventure trying to fix that at first. stripslashes() is much nicer.

  12. Kevin Fox July 15, 2010 03:03

    I’m getting this error, does anyone know what it means, and how fix it?

    securityErrorHandler: [SecurityErrorEvent type="securityError" bubbles=false cancelable=false eventPhase=2 text="Error #2048: Security sandbox violation: http://www.foxflare.com/twitter/App.swf cannot load data from http://twitter.com/statuses/update.xml."]

    Here is where my app is located:
    http://www.foxflare.com/twitter

    I’m using BlueHost as my ISP, and I remember asking about proxy, and the rep said they don’t allow it. Unfortunately I don’t know about proxy concepts at all, so I don’t know what he’s talking about. Could this proxy denial thing be the culprit here?

    Jozef thanks for offering another great solution. Your Facebook OAuth2 solution was great and I was relieved when I saw that you took on Twitter as well. I searched for days and it appears you’re the only guy coming up with practical approaches for this stuff.

  13. Jozef Chúťka July 15, 2010 10:00

    @Kevin, security error 2048 means you have to download crossdomain.xml from the targeting domain before using the actual data content. you can bypass this by using proxy.php and make your server side do the foreign request

  14. Jozef Chúťka July 15, 2010 10:05

    @Kevin your ISP may block proxy servers that routes all your traffic, but that is not our case, proxy.php will work for you just fine.

  15. Kevin Fox July 15, 2010 20:55

    I figured out what I did wrong. There were some variable types that were changed properly or not overridden properly etc. :p

  16. Dave August 5, 2010 03:56

    Hey I am trying to get this running locally with no love. I am using a .local address, could this be the issue? Nothing seems to be happening after calling connect from twitter.connect();

  17. Jozef Chúťka August 9, 2010 10:11

    hi Dave,
    - does my app work for you?
    - could you debug twitter.connect function, where the script finishes exactly?
    - does ExternalInterface call get eecuted?
    - do you have popup blocker?

  18. e-sushi August 16, 2010 05:37

    Hi there! Cool info but I’m a bit confused, so…

    Question: why do you use “air talks to php talks to twitter”? Isn’t there any way to use oauth from within an air app without using any “external stuff” like php on a webserver? Maybe I’m missing something here, so any info would be great!

    Tnx
    Mike

  19. Jozef Chúťka August 16, 2010 09:30

    hi @e-sushi. This class was originaly writen for flash player (.swf) files, not air. While twitter does not provide crossdomain poliecies required for flash player, you can not make direct requests and catch response. However, you can use AIR to make requests directly without backend, just google some oauth actionscript class and you are fine.

  20. Ben. September 2, 2010 20:19

    Hi,

    first thank you for this tutorial, it’s very helpful for me. Second, I try to show the user info, but when the user click on connect button and when he is connected how can I get his idUser ? Because when you call the loadInfo() methods you need to have a userId.

    Thanks.

    Ben.

  21. Ben. September 3, 2010 13:13

    Ok, I find the method verify() ;-) You can test here : http://bigbenprod.fr/visiotweet/

    Ben.

  22. Vincent September 8, 2010 16:52

    Hi Jozef,

    Nice class, thanks !

    Did you know how to get userId after get connected ? I need that to display infos from the user, and the function in twitterscript loadInfo need userId string.

    And did you know if there is an autoconnect function to detect at the beginning of the app if the user is connected? like your facebook stuff.

    Thanks by advance

    Regards

  23. Jozef Chúťka September 9, 2010 10:07

    Hi @Ben,
    yes it is verify_credentials ( http://apiwiki.twitter.com/Twitter-REST-API-Method:-account%C2%A0verify_credentials -> http://api.twitter.com/1/account/verify_credentials.xml ) method
    It is very nice app you have created

  24. Jozef Chúťka September 9, 2010 10:42

    Hi @Vincent, please check out my previous comment (verify credentials method) for getting actual user. In order to use autoconnect you may do the following:
    1. store access token into a cookie or SharedObject with your first login
    2. modify the proxy.php to use access token from cookie or SharedObject (pushing)
    3. when your apps starts again try verify_credentials with stored access token, it may be valid for some time

  25. Vincent September 9, 2010 15:11

    Hi @Jozef,

    Thanks for your trick, i have used the method of Ben, verify(), works well

    I try for finish to disconnect my user, there is a function called endSession() in twitter api, works welle but did’nt do the job i want, the token seems to be always hee, and when i reload the page, and get connected.

    The trick in this link seems a bit difficult http://stackoverflow.com/questions/1960957/twitter-api-logout

    Did you have an idea for your class?

    thanks

    Regards

  26. Jozef Chúťka September 9, 2010 15:22

    Hi @Vincent, @Ben, what exactly is verify() method? I am a bit confused now – I can not find any method called “verify”. Do you refer to verify-credentials or some different method?
    In order to log out, clean access_token from your _SESSION variable, once the token is trashed, that should do the trick

  27. Vincent September 9, 2010 17:39

    Jozef,

    public function verify():void {
    var verifyLoader:URLLoader = this.getLoader(VERIFY);
    verifyLoader.load(twitterRequest(VERIFY_URL));
    }

    line 387 in Twitter.as

  28. Jozef Chúťka September 9, 2010 17:57

    @Vincent, thnx, my mistake, I can see it now… it actually calls the verify-credentials

  29. Dan September 22, 2010 01:36

    Hi Jozef,

    thanks for your work. Seems very promising.
    Unfortunately I’m a total php noob and when I click on connect in version of the application this website opens:

    http://github.com/abraham/twitteroauth/blob/master/twitteroauth/twitteroauth.php

    I’m sure some of my configurations are wrong. Can you please give me a hint on where to look?

    Thank you ;)

  30. Jozef Chúťka September 22, 2010 11:49

    Hi Dan,
    - does that happen when you click connect in my application or in your one?
    - did you copied correctly content of connect.php file and other files into your php server?

  31. Frank September 29, 2010 13:48

    Hi Jozef,

    in my app the connect-popup shows just a white page. I couldn’t figure out exactly what it it, but it seems that the code stops working after the following line in twitteroauth.php line 186:
    $request->sign_request($this->sha1_method, $this->consumer, $this->token);

    when I echo $this->sha1_method script stops. Any ideas what this means?

    best wishes,
    Frank

  32. Jozef Chúťka September 29, 2010 14:54

    Hi Frank,
    please turn your php errors on (E_ALL) and debug the error
    these .php classes are not developed by me, please contact the author on http://github.com/abraham/twitteroauth/tree/master/twitteroauth/

  33. Kcal January 1, 2011 15:00

    Is there a way to stripslashes from tweets before posting them with OAuth? Thx!

  34. Jozef Chúťka January 3, 2011 11:43

    Kcal, sure you can, just override setStatus function and strip whatever you want

  35. Robert January 22, 2011 16:03

    Hi guys,
    I found there’re errors in the code like wrong references and others. some that I found was:
    - can’t find com.twitter.api.Twitter rather twitter.api.Twitter (any source in as format that is around for the Twitter API? because I got the SWC only)
    - this bit is wrong override protected function addLoader – it says nothing to override and also the last line should’ve been loader rather than loaders
    - would probably be easier if someone could convert this to AS based rather than flex if you mind?

    Please help me. thanks in advance.

  36. Jozef Chúťka January 31, 2011 12:09

    Hi Robert,
    yes I am referencing external library (official Twitter one) … You can not use .swc because you need to change some code inside as described in step 8. So you should go to http://code.google.com/p/twitterscript/ click source / browse / trunk / src… and download sources directly than made some changes as described in step 8 (addLoader function to protected etc.).

    my TwitterLogger class should work for you with flex compiler, with cs one you should remove [Bindable] metadata and its ok to go…

  37. [...] insightful and helpful tutorial of setting up the OAUTH, proxy and all its necessary backend stuff. Here it is.  The steps are quite simple, I managed to set the whole thing up within minutes. It uses flex, [...]

  38. Dan September 4, 2011 13:29

    Hey man,

    thank you very much for sharing your work. I really appreciate it.
    I have one question though. (Maybe I just can’t see the forest for the trees)

    Once I have connected I’d like to show the username (screen_name) of the connected user.
    But in the event handler for the CONNECTED event the data object is null.

    So where to get the users information from?

    Any help would be highly appreciated.

    Thanks a lot and keep up the great work!

    Cheers,

    Dan

  39. Jozef Chúťka September 4, 2011 19:38
  40. Helliax August 2, 2012 00:08

    I’ve got the php code under a different domain than the SWF part, and I’m running into a permission denied error when it’s trying to call the ‘confirmTwitterConnection’ ExternalInterface. I’ve got Security.allowdomain(“*”) in the swf, and allowScriptAccess=”always” in the HTML page hosting the SWF.

    Do you know off-hand if there is some other security param I need to watch out for?

  41. Jozef Chúťka August 2, 2012 09:01

    hi Helliax,
    confirmTwitterConnection is an javascript function defined from actionscript. Not quite sure where is your html wrapper for flash hosted from and hard to guess but I think the javascript part is defined in different domain than it is later called from. What is the actual error? is it javascript error or actionscript one?

  42. Helliax August 3, 2012 00:34

    Jozef, thanks for such a fast reply. I figured out why the error is happening. It’s a javascript crossdomain issue, I believe. confirmTwitterConnection() is on domainA, and callback.php is on domainB (not just different subdomains).

    It is a javascript error, and I was looking in the wrong place (the actionscript). I’ve looked online a bit, and there seem to be a few hacks here and there to bypass the javascript permission, so I’ll have to try them out. I don’t know if they work.

  43. nite December 11, 2012 12:35

    hi how to send pics throught twitter update media from this example thanks

  44. Jozef Chúťka December 11, 2012 14:02
  45. shane February 27, 2013 09:12

    hi how to call user friends data from flash

  46. Jozef Chúťka February 27, 2013 10:29

    hi shane, I have not used twitter api for longer time now, from time to time I just hear how unreliable it is. anyway, if you want to proceed I would suggest starting at https://dev.twitter.com/docs/api/1.1

  47. Felipe April 1, 2013 20:17

    Hi, thanks for share this.

    Can you put some link to download this example? i’ll really appreciate that.

    Thanks.

  48. Jozef Chúťka April 2, 2013 09:33

    hi Felipe,
    You can download some sources by following the links in the article- Other than that, I belive article contains all the necessary. if you go through the article carefully and has some base knowledge about these technologies, you should be able to make the app yourself.

  49. Boleslav June 7, 2013 12:56

    Hello. i have trouble with popup window after logging. it has not closed. and i receive “You may now close this window.” message
    mb you can provide your actionscript example source code?

  50. Boleslav June 7, 2013 14:52

    i have solved an issue :) sorry for inconvenience

  51. Shane September 26, 2013 10:54

    hi josef

    i tried with twitter.search(“#spiderman”)

    but it is giving me this
    Implicit coercion of a value of type String to an unrelated type com.twitter.api:TwitterSearch.

  52. Jozef Chúťka September 26, 2013 11:25

    hi Shane,
    have a closer look at Twitter.as and search() method:
    search(query:TwitterSearch):void
    means you have to create instance of TwitterSearch and pass it into the search method

  53. Shane April 11, 2014 11:17

    @Boleslav how did u solved the issue of popup window of this “You may now close this window.” message

    @Jozef my callback url in twitter app is https://mysite.com/index1.html
    when i test my app in this link it works fine i connect to twitter the popup goes and my app loads.

    but the same thing when i try with http://mysite.com/index1.html the popup window stays and message appears You may now close this window and nothing happens

    will u help me in solving this

  54. Jozef Chúťka April 12, 2014 09:20

    hi Shane, there might be a crossdomain issue b/c of http vs. https. Make sure your main app is on the same protocol as twitter callback. If not, redirect twitter callback to proper protocol. You can use chrome developer tools to debug the crossdomain or any other javascript issue

  55. Shane April 15, 2014 09:27

    hi josef thanks for the reply

    I have my proxy.php,config.php,connect.php,App.swf and callback.php on the same domain folder http://mysite.com/shane/newdata/index1.html. In newdata folder all the files are there.

    I have crossdomain file on http://mysite.com/crossdomain.xml

    My callback url in twitter apps is https://mysite.com/shane/newdata/callback.php

    when i try with https://mysite.com/shane/newdata/index1.html it works
    but this doesnt work http://mysite.com/shane/newdata/index1.html it shows you may close the window text.

    dont knw much about php so dont know how to redirect twitter callback to proper protocol.

  56. Jozef Chúťka April 15, 2014 11:39

    Shane,
    as you write, part of your stuff is on http while callback is https which may cause some crossdomain issues. You either put all your stuff to http or https. If that is not possible you might want to redirect callback from one to another, do not forget to redirect all necessary GET/POST params as well, you might want to handle it in url fragment so you do not expose sensitive data over http. redirect in php can be done via header() method, you can also do redirect via javascript, or refresh meta in html header

Leave a comment

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