Web Developer / Blog

31st, 2009

How to quickly integrate with Twitter’s OAuth API using PHP

Digg this article · Save to del.icio.us · Stumble it!

UPDATE: You can watch me on GitHub, view documentation or fork the project.

A new project I’m working on integrates closely with Twitter. As a result, I become a lot more familiar with OAuth than I care to. Many developers want to be able to speak the OAuth protocol without having to know the fine details. I am deviating from the normal order by starting with an example and explaining it afterwards. If you are interested in using “Sign in with Twitter” then read my other blog post.

A simple example
To follow the example, you’ll need to download these files and have a web server set up. I use my laptop but you can also use a webhost if you’d like. Head over to Twitter and set up an application. The last two fields are important. The callback url will need to redirect to your web server at a location where you will be uploading some files. Assuming you’re going to upload into your web root, the callback url would be something like http://yourdomain.com/confirm.php. You’ll also need to make sure you select “Read & Write” access.

Once you click save, you will be presented with some information. Download the php files for this example and open secret.php. Enter your consumer key and consumer secret in the appropriate areas. Save and upload to your webserver.

Open a browser to your webserver’s start.php file you just uploaded. You’ll see a link to authorize with Twitter. Clicking on that link will take you to Twitter’s site and ask you to log in if you’re not already.

Oauth Flow

Once you click Allow you’ll be redirected back to your site with a custom greeting pulled straight from Twitter. It doesn’t get much easier than that. From here on out you can use the token and secret provided by Twitter to access the API on behalf of the user who authorized you. Now, the details.

Why use OAuth…the benefits
OAuth is “an open protocol to allow secure API authorization in a simple and standard method from desktop and web applications.” What’s that mean? In short, it means that a user of your service can provide you limited access to a third party account of theirs. OAuth is often described as a valet key that your users can give you to access their accounts on other services. For example, a user using Flickr (the service provider) would provide Snapfish (the consumer) with read only access to their Flickr account. This lets Snapfish access photos in the user’s Flickr account so they can order prints.

It’s all in the tokens
How does this happen without asking the user to give up their Flickr password? The flow would start by Snapfish obtaining a consumer key and secret and using them to generate an authorization link to Flickr. Once the user follows the authorization link, they are asked to log in on Flickr’s site. Once logged in they can choose to grant Snapfish access to their Flickr account. Flickr then marks the request token as having been authorized by the user. Snapfish uses the request token to obtain an access token which can be used by to make requests to Flickr on behalf of the user. This diagram may help visualize it easier. C = Consumer, SP = Service Provider

Oauth Flow

Let’s dive in
I had several goals in writing a PHP client for OAuth and Twitter.

  • The two should be decoupled, making it easier to add other OAuth services
  • Reuse the asynchronous/non-blocking curl library
  • Expose methods which would enable OAuth requests in less than 4 lines of code

Generating a valid OAuth request
It turns out that generating an OAuth request is very simple but debugging it is a pain. Every OAuth request contains certain parameters. These include:

  • oauth_consumer_key
  • oauth_token
  • oauth_nonce
  • oauth_timestamp
  • oauth_signature method
  • oauth_version
  • oauth_signature

These can be passed in as GET or POST parameters or in the Authorization header. You’ll most likely be passing in other additional parameters based on the API you’re accessing. I won’t get into the details of what these parameters represent in this blog post but it’s good information to know.

A look inside EpiOAuth
EpiOAuth initializes an instance of the EpiCurl object in its constructor. Since EpiCurl is not included, you’ll want to make sure you’ve made it available ahead of time. There are several methods which you’ll need to know about.

  • getAccessToken
  • getAuthorizationLink
  • getRequestToken

If you reference the diagram above, then these should be self explanatory. There are several other helper methods which act more behind the scenes but play an important role.

  • generateSignature
  • generateNonce
  • httpRequest
  • prepareParameters
  • signString

These do all the magic to turn an otherwise normal request into a valid OAuth one.

How EpiTwitter extends EpiOAuth
Per my original goal, the Twitter class should contain a very minimal set of functions which call specific endpoints. These methods are self explanatory if you look at them as well. I did, however, want to make it easy to use the class in an asynchronous manner since the underlying http library I was using supports it. This led me to create an EpiTwitterJson. When you make a request you’ll receive an instance of the EpiTwitterJson object without blocking for a response from the Twitter API. You can at any point access individual elements in the response as a member variable. Accessing the member variable with return the value and block if needed.

Wrapping it up
This should help get you up and running. The code provided is very much under construction. I would greatly appreciate contributions to make it better.

If you’re interested in learning more about OAuth then there’s a great set of articles located at http://oauth.net/documentation/getting-started.

Comments are closed on this post. If you find a bug, please open an issue on GitHub.

161 Responses to “How to quickly integrate with Twitter’s OAuth API using PHP”

  1. Adam Evers Says:

    Nice. This worked well for me. For some reason I couldn’t get the one from -> http://apiwiki.twitter.com/OAuth-Examples to work.

    I am having trouble figuring out how to store the token and then reuse it for further api calls. Any suggestions?

    Thanks for all your work so far. Looks great.

  2. jaisen Says:

    @Adam, If you have a look at confirm.php in the zip file, you’ll see following on line #11.

    $twitterObj->setToken($token->oauth_token, $token->oauth_token_secret);

    oauth_token and oauth_token_secret are your access tokens for the account that was authenticated with Twitter - save them. Later, you can use these values by passing them in as the 3rd and 4th parameters to the constructor or use the setToken method as in the example.

    Hopefully that helps, let me know if you have any other questions.

  3. Adam Evers Says:


    Perfect. That worked. Here’s my code. For anyone that wants to see it …

    $twitterObj = new EpiTwitter($consumer_key, $consumer_secret);
    $twitterObj->setToken($user[1], $user[3]);
    $twitterInfo = $twitterObj->getUserInfo();

    $user[1] and $user[3] are variables from the database.

  4. Arik Says:


    I’ve started to use your lib for a small app I’m building and noticed a bug when trying to do a GET request and another one when the response is an array.

    For the first one there’s a simple fix for the other one I did an ugly hack, and would love to discuss with you a better solution. I will really appreciate if you could contact me by my email, or over Gtalk (arikfri).

    Thank you for the tutorial and code, btw!

  5. Michael Says:

    Hey, just wanted to say thanks for this.

  6. wirawan Says:


    I want to ask about the PHP version.
    Is it working on PHP4?

  7. jaisen Says:

    @wirawan, I haven’t checked if this works with PHP4 but my guess is that it doesn’t. It might be a trivial exercise to make it backwards compatible. I don’t have plans to do that, but if you do then let me know and I’ll include the PHP4 versions along with the current ones.

  8. Daniel Brierton Says:

    I seem to be having a problem with this… I’m using the same as Adam above:

    $twitterObj = new EpiTwitter($consumer_key, $consumer_secret);
    $twitterObj->setToken($user[1], $user[3]);
    $twitterInfo = $twitterObj->getUserInfo();

    $user[1] and $user[3] are variables from the database.

    It works perfectly for setUserStatus, but returned an error of “This method requires a GET”, on changing it to a get, the calls cannot be authenticated

  9. jaisen Says:

    @Daniel, could you show me your getUserInfo() method?

  10. Daniel Brierton Says:

    Sure, it’s:

    public function getUserInfo()
    return new EpiTwitterJson($this->httpRequest('GET', 'http://twitter.com/account/verify_credentials.json'));

    It was POST, and then got the error saying it has to be GET and then I got the Authentication error… It could possibly be a problem on Twitter’s end?

  11. Arik Says:

    @Daniel - Twitter just pushed an update to the API that stricts the method for each call, i.e. - GET methods can no longer be sent as POST methods (verify_credentials is a GET method).

    Re. why you getting the authentication error - in EpiOAuth.php you need to move lines 59+60 to come before line 49.

  12. Daniel Brierton Says:

    Thanks a million! It’s working perfectly now :)

  13. jaisen Says:

    @Arik, Thanks! Have you fixed any other bugs? :)

    If you can commit the changes to allow access for enumerated arrays as responses then I’ll merge your changes. Else, I might just add what we talked about.

  14. Arik Says:

    @Jaisen, I planned commiting my fixes earlier today, but then I had to handle some issues with my app (Topify). If I’ll see that I don’t have time for it anytime soon, I will send you my version by mail.

  15. Kosso Says:

    Yup. The ‘verify_credentials’ API call has changed from a POST to a GET.

  16. jaisen Says:

    I made some significant updates and included @Arik’s bug fix. Every endpoint should now be supported.

    Please see the documentation for usage notes: http://wiki.github.com/jmathai/twitter-async

  17. Andy Says:

    I tried the new code, still no luck :(

  18. Photo Sharing Says:

    Great work on this. Very helpful!

    I’ve created a quick EpiTwitterXML class since I require XML instead of JSON responses. I’ve added this to the bottom of EpiTwitter.php

    class EpiTwitterXML {
      private $resp;
      public function __construct($resp) {
        $this->resp = $resp;
      public function __get($name) {
        return $this->resp->data;

    I also replaced ‘.json’ with ‘.xml’ on line 14 and replaced ‘return new EpiTwitterJson’ with ‘return new EpiTwitterXML’ on line 18

    Hope this helps someone. It would be nice to support both XML and JSON in a future version (my solution only replaces JSON with XML)

    Have fun.

  19. Photo Sharing Says:

    Quick question. I’ve got the code working (authorizing, storing tokens to database, sessions, reusing tokens later etc).

    My app lets users view photos (and I’m storing the twitter userId along with the photo). I can’t get the API to pull out the users data (/users/show?user_id=1234) when a user is not authorized. I get invalid session token (because the user isnt authorized).

    Simply viewing a photo and calling the users/show method should be available to all users, not only once they’ve authorized.

    This isn’t a problem with your code - it’s perfect. I’m just wondering if my best solution is to create some cURL functions to access the REST API (and skip the token/authorization stage) and keep OAuth for authorized requests (posting tweets, login etc)

    Any help is appreciated :) Thanks and great work

  20. Daniel Brierton Says:

    I updated the EpiOAuth and EpiTwitter… And I couldn’t get it to work, so I rolled EpiTwitter back to the old one, changed methods where needed and created new functions to get the friends timeline, repies etc. I’m still using the new EpiOAuth All those work fine, but posting new updates doesn’t work.

    It’s the same as it was in the original EpiTwitter:

      public function setUserStatus($status = null)
        if(empty($status) || strlen($status) > 140)
          return false;
        return new EpiTwitterJson($this->httpRequest('POST', 'http://twitter.com/statuses/update.json', array('status' => $status)));

    I keep getting “Failed to validate oauth signature or token”. Perhaps EpiOAuth isn’t working right for POST methods..?

  21. jaisen Says:

    Looks like a bug with Twitter’s API for POST method endpoints. Several people using various libraries began reporting that POSTs stopped working.

    There is an open bug on it here: http://code.google.com/p/twitter-api/issues/detail?id=447

    @Daniel, the new version is working fine for me. Could you let me know what errors you were getting for the friends timeline that worked in the old version but not the new?

  22. Daniel Brierton Says:

    I got it working now. Before I could just use $friendsTimeline in a foreach, now it has to be $friendsTimeline->response instead.

    And, I guess it’s just a matter of sitting back and waiting for the POST bug to be fixed

  23. jaisen Says:

    @Daniel, I definitely suggest using the new version. Once I merge in some changes from Arik you’ll be able to foreach over the returned value and not have to rely on ->response.

  24. Vaibhav Says:

    Getting this url after changing secret.php data in start.php http://twitter.com/oauth/authorize?oauth_token=

    Where is oauth_token missing?

  25. Daniel Brierton Says:

    Yeah, I’m using it now. Thanks for the great work. I’ll keep an eye out for newer versions :)

  26. jaisen Says:

    @Vaibhav, did you remove the {}’s from the key and secret in secret.php?

  27. Greg Says:

    @wirawan @jaisen My server/host is using PHP 4.4.7 and I’m not able to get this working. Just FYI.

    I get:

    Parse error: syntax error, unexpected T_CONST, expecting T_OLD_FUNCTION or T_FUNCTION or T_VAR or ‘}’ in /usr/home/ebar277/public_html/mobile/cgi-bin/oauth/EpiCurl.php on line 4

  28. Matthew Gamble Says:

    I updated to the latest version, and when I’m trying to get the authorization URL by using $twitterObj->getAuthorizationLink() I’m getting this error:

    Catchable fatal error: Object of class EpiTwitterJson could not be converted to string

    I looked at the object, and it’s null:

    object(EpiTwitterJson)#3 (1) { ["resp:private"]=> NULL }


  29. Matthew Gamble Says:

    Figured it out - in the updated version you renamed getAuthorizationLink to getAuthorizationUrl.

    Thanks for all the great work on this!

  30. Daniel Brierton Says:

    Has anyone come up with a temporary solution to the problem with POST methods? Or is this entirely in Twitter’s hands?

  31. Dan Morin Says:

    So the problem with the POST is not twitter, it’s this library. Changing your httpPost method in EpiOAuth to the following should make it work:

    final private function httpPost($url, $params = null)
        $params['oauth_signature'] = rawurldecode($params['oauth_signature']);
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_POST, true);
        //curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
        $resp  = $this->curl->addCurl($ch);
        return $resp;

    If that doesn’t come through for some reason, the changes are to rawurldecode the $params['oauth_signature'] value and to change the POSTFILEDS to use http_build_query which will use the correct form type.

  32. Daniel Brierton Says:

    Thanks Dan,
    I tried that and it works perfectly! :)

  33. Dan Morin Says:

    Anyone have any luck posting non-ascii characters in a status update? I have mb_string functions overridden which usually causes problems with encryption, but I can’t figure out where it’s breaking.

  34. jaisen Says:

    @Dan, thanks for the tip. I had a lot of back and forth with the Twitter devs today. I’m going to commit an update that puts all the OAuth fields in the header of the request. I’ll also have some unit tests to debug this easier in the future.

    There was a bug on Twitter’s end that should be pushed tomorrow for non-ascii characters.


  35. jaisen Says:

    Here’s the update which puts the OAuth parameters into the header of the request. I’ve also added unit tests for EpiTwitter and EpiOAuth that you can run with phpunit.


    This should be completely backwards compatible. Thanks for the tips and helping me find the bug.

  36. Jochem Prins Says:

    Nice work! Thanks, will probably use it for the OAuth implementation in my projects.

  37. jaisen Says:

    @Sam, Just noticed that your comments were flagged as spam (doh!).

    If you’ve created support for XML then feel free to fork the repository and send me a pull request. It would be nice to add XML support for everyone to use.

    I didn’t quite understand your dilemma. What photos are you referring to?

    I’ve published several important updates since your last comment which fixed a bug with POST requests.

  38. Sam Wirah Says:

    No problemo dude. Like I said on twitter (@wirah) everythings working perfectly now. I also realised there was actually no need for me to use XML and an XML parser as the json_decode function builds us a nice array from the response already.

    One thing that confused me was my line:

    $update_status = $twitterObj->post_statusesUpdate(array('status' => $status));

    wasnt updating the status unless I made a reference to $update_status->response

    Works great if I add this line below though:
    $temp = $update_status->response;

  39. Darwin Says:

    I’ve trying to use the
    get_statusesFriends_timeline(array(’since_id’ => $LastID) and it’s not working it’s returning the a twitter page with “Something is technically wrong.”

    I can use OAuth to get get_accountRate_limit_status(); So I’m sure the authentication is right
    I can curl it on command line with Basic Auth and it comes back ok using this URL ‘http://twitter.com/statuses/friends_timeline.json?since_id=152565984′
    which I cut out of the EpiOAuth httpGet function $url.

    Am I missing something here?

  40. jaisen Says:


    I tracked it down to a bug in the OAuth realm header parameter. It affected all GET requests with a parameter.

    I’ve fixed it and committed to GitHub. Thanks for reporting the bug.

  41. Darwin Says:

    Thanks for your quick response and fix.
    That took care of it.

    One more question.
    Using $data = $t->get_statusesMentions(array(’since_id’ => $LastID, ‘page’ => $page));

    If twitter is down or the authentication fails or there are no new tweets since the last check. What should I be looking for in the returned $data to indicate no new tweets?

  42. jaisen Says:

    @Darwin, there are two options you have. You could check the $resp->response->code to make sure it’s 200 (or another if expected). You also have access to the raw response in $response->responseText.

    I’m not thrilled about how errors are currently exposed. I’ve thought of several options, one being throwing custom http exceptions if it’s not in the 2xx family. The implementer could then catch and handle them as they see fit. But as Arik had pointed out, not all non-2xx responses are errors.

    I’m definitely open for suggestions :). I probably wouldn’t add anything in until I felt really good about it.

  43. jaisen Says:

    Github just released an integrated issue tracker. Feel free to open any bugs you find. http://github.com/jmathai/twitter-async/issues

  44. Citynumbers Says:

    Is the version for PHP 4.x available yet?

    I also get this error now:
    Parse error: parse error, unexpected T_CONST, expecting T_OLD_FUNCTION or T_FUNCTION or T_VAR or ‘}’ in /home/content/c/i/t/cityhopper/html/EpiCurl.php on line 4

  45. Brant Says:

    I am trying to follow along with what you guys are doing but I am a bit confused. I can’t seem to tie in everything together.

    What I am trying to do is always authenticate as a particular user and automatically post new status updates.

    Would someone be so kind as to make a basic how-to for this script for n00bs like me? :)

  46. Rahul Says:

    So the user will have to click on “Sign in with twitter” everytime they come to my site. So whats the advantage of saving the token and secret token in the database…

  47. jaisen Says:

    @Brant & @Rahul, you need to save the token and secret that you get back from Twitter (->oauth_token and ->oauth_token_secret in confirm.php). Once you save those, you can pass them along with subsequent requests to authenticate as that user. The user does not need to go through the steps of authorizing your application a second time.

    @Citynumbers, no PHP 4 version is available at the moment (or in the near future).

  48. Rahul Says:

    thanks for a quick reply.
    I come in the first time click on sign in with twitter, twitter does its things send it back to my page. I save the 2 tokens in the database against the user. in that session the user wont have to go through that process again. But when the same user comes to my site on a different day from a different computer they would have to do the twitter auhtorizing again right?

  49. Sam Says:

    Hi jaisen, I’m having a problem.

    $twitterObj = new EpiTwitter($consumer_key, $consumer_secret, $oauth_token, $token_secret);
    $twitter_user = $twitterObj->get_accountVerify_credentials();
    print_r($twitter_user->response); // SUCCESSFUL
    $trends = $twitterObj->get_trendsCurrent();
    print_r($trends->response); // FAIL - Unauthorized application or token

    Im confused why it verifies the user’s data - but the next time I try an API call it fails.
    Posting tweets also works fine. The tokens are definitely correct (otherwise verifyCredentials would fail)

  50. Sam Says:

    Cracked it. Realised EpiTwitter is requesting http://twitter.com/trends.json instead of http://search.twitter.com/trends.json

    Is the Search API implemented in EpiTwitter?

  51. jaisen Says:

    @Sam, the search API isn’t implemented. It would be trivial to do though. I’ll read up on it and add support. I don’t believe it requires authentication (right?).

  52. Kiran Says:

    When i try to update user status, i get this error:
    “Failed to validate oauth signature or token”


    I tried your solution (httpPost).
    That leads to the following error:
    ( [request] => /statuses/update.json [error] => Could not authenticate you. )

    Any pointers?

  53. Dan Morin Says:

    My post original comment is probably not longer relevant as I believe those bugs were fixed in a library updated.

  54. jaisen Says:

    @Kiran, @Dan’s correct that the library was updated to fix the problem he was having. Are you using the latest code from github?

    Do you have source you can point me to?

  55. Sam Says:

    Hey jaisen.
    None of the Search API needs authentication.

    I’m not sure whether we still need to send our oauth_token though (for twitter tracking which apps are using the search api)

  56. Rahul Says:

    I come in the first time click on sign in with twitter, twitter does its things send it back to my page. I save the 2 tokens in the database against the user. in that session the user wont have to go through that process again. But when the same user comes to my site on a different day from a different computer they would have to do the twitter auhtorizing again right?

  57. Rahul Says:

    have a look at http://www.twittercontd.com/index_test.php

  58. jaisen Says:

    @Rahul, once you save the token and token secret…the user will not need to re-authorize again.

    I tested your link and was able to update a status. However, if I refreshed the page it did not seem to maintain a session for me to post another update.

  59. jaisen Says:

    @Sam, cool. I’ll add support for the search API w/o OAuth. I’m unfamliar with it but it should be straightforward.

  60. Sam Says:

    It looks like it’s just a different api url. http://search.twitter.com rather than http://twitter.com
    the same get_trendsCurrent() method translating to /trends/current.json can still be used it seems.
    loving epitwitter!
    just looking at the code is helping with my php too. i never knew about __call()

  61. Kiran Says:

    Seems to work now.
    I logged into my twitter account, and revoked permissions on my app, and tried the whole thing again. This time it worked.

    Thanks for library. Awesome!

  62. Rahul Says:

    I fixed the session state but I still have that question. Once the user authorise the app the second time around why does it ask “Deny or Allow”

  63. jaisen Says:

    @Sam take it for a test drive and let me know how it works.


  64. Bernard Jason Berras Says:

    sir im having this kind of problem…

    Fatal error: Call to undefined function curl_init() in C:\wamp\www\1\twitterOAuth.php on line 126

    anywork around to fix it?
    pls email me @ deathgroove@gmail.com

  65. Bernard Jason Berras Says:

    can u help me with this i error thing….

    Warning: require_once(PHPUnit/Framework.php) [function.require-once]: failed to open stream: No such file or directory in C:\wamp\www\123\php\tests\EpiOAuthTest.php on line 4

    Fatal error: require_once() [function.require]: Failed opening required ‘PHPUnit/Framework.php’ (include_path=’.;C:\php5\pear’) in C:\wamp\www\123\php\tests\EpiOAuthTest.php on line 4

  66. alon Says:

    hey, im stuck with the unicode twits right now. classic bug that i cant resolve. english twits go fine. unicode hebrew ones return Failed to validate oauth signature or token

    can anyone help? i saw there was a ruby fix but i cant seem to implement it on this library.

    help :(

  67. Ashish Says:

    Anyone getting this error?

    Parse error: syntax error, unexpected T_CONST, expecting T_OLD_FUNCTION or T_FUNCTION or T_VAR or ‘}’ in /homepages/29/d204945174/htdocs/quizhubb/epi/EpiCurl.php on line 4

    Was working just fine last night =/

  68. Ashish Says:

    Silly me…server was running PHP 4. Runs fine on PHP 5!


  69. jaisen Says:

    @alon, can you paste in the string you were getting errors with? I’ll have a look at fixing it.

  70. jaisen Says:

    I merged Arik’s code, which lets you deal with enumerated lists more naturally, into the master branch. This applies to endpoints like /statuses/followers.

    Documentation has been updated as well: http://wiki.github.com/jmathai/twitter-async.

    Please give it a try and report any issues here or directly at github - http://github.com/jmathai/twitter-async/issues.

  71. alon Says:

    @jaisen try updating a status with unicode text like
    בוקר טוב

    it will fail on authentication. i understood there was a fix for ruby for that. couldnt implement it for php.

    $twitterObj = new EpiTwitter($consumer_key, $consumer_secret, $usertoken, $usersecrettoken);
    $userInfo = $twitterObj->get_accountVerify_credentials();

    $followers = $twitterObj->post_statusesUpdate(array(’status’ => $status));

    return $followers->response;

  72. alon Says:


  73. pete Says:

    @sam @jaisen

    I test drove the search method - worked fine while authenticated with twitter.

    Is the code setup to allow search to work while not authenticated? I can’t get it to work atm but think it should be able to.

    I have called:
    $twitterObj = new EpiTwitter($consumer_key, $consumer_secret);

    and am trying:
    $statuses = $twitterObj->get_search($search_terms);

    which only works when authenticated…

  74. jaisen Says:

    @pete, mind checking to see if you’re being rate limited? Have a look at $statuses->responseText. I ran into this on Friday. If not, what’s responseText contain?

  75. jaisen Says:

    @alon, thanks for the tip. Fixed the problem and added unit tests for unicode support. Pushed to github.

  76. pete Says:

    @jaisen was my bad - fixed it now. will think twice before posting late at night…

    thanks for the great package btw

  77. Mwd Says:

    Thanks , this worked for me to add the app to twitter with OAuth…

    It’s twitter mobile


  78. Tom Says:

    @jaisen Thanks alot for this code.

    I updated my code to the latest released an encounter this error ‘Warning: Invalid argument supplied for foreach() in /home/.liebchen/username/domain/oauth/EpiTwitter.php on line 91′

    I updated because I was having the ‘Failed to validate oauth signature or token’ when trying to post a status update.

    I could get account credentials fine but when I called $twitterObj->post_statusesUpdate($params); directly afterwards I got the failed to validate problem.

    Thanks for your time.

  79. Tom Says:

    Please disregard my last post as it turns out I was failing to call

    $token = $_twitterObj->getAccessToken();
    $_twitterObj->setToken($token->oauth_token, $token->oauth_token_secret);

    after I had set the token via get parameter.

    All is fine now. Thanks again.

  80. Daniel Brierton Says:

    What are you using in the foreach. I was having that problem before. I was using:
    $tweets = $twitterObj->get_statusesFriends_timeline();

    foreach($tweets as $tweet)
    but had to change it to
    foreach($tweets->response as $tweet)
    to get it to work.

    Meanwhile I’m having trouble with search methods. Is
    $searchResults = $twitterObj->get_search(array(’q’ => $_GET["q"]));
    the right way to do it?

  81. Daniel Brierton Says:

    Ok, disregard that… All working :) Sorry, wish this had edit and delete buttons :P

  82. jaisen Says:

    @daniel, no problem. fyi - the latest version let’s you do:

    foreach($tweets as $tweet) echo $tweet->text;

    No longer required to use ->response.

  83. phil davis Says:

    After a bunch of tries This works just great.

    Thanks for your work.

    It seems that the only way I could get

    $userInfo = $twitterObjforSend->post_direct_messagesNew($directmessagearr);

    to work was by reading

    Does that make any sense?

  84. jaisen Says:

    @phil, that’s correct. It’s part of the asynchronous nature of how this library works.

    You need to read responseText (or any of the other response values) to ensure that the call was successful.

    The benefit of this is that you can make the call, go about doing some other work and come back to retrieve the response. Most libraries will make the call and wait until a response is received prior to moving on.

    Glad it’s working out for you.

  85. Umed Says:

    Hi there. thanks you very much for tutorial and api itself.

    well I faced to isue that makes me crazy. The application works fine but when the user logs out from my application and login again Twitter asks me wheter I allow app to access my account or not.

    I have seen several sitest that just retrives user back if he is currently logged at twitter.

    Thanks in advance,

  86. Rav Says:

    I just got the latest code for the example provided. I registered a new application and replaced the consumer key and consumer secret. However, the authorization link in the start.php file keeps coming up with a blank oauth token parameter. I guess getRequestToken is not returning a token. Any ideas?

  87. Umed Says:

    ok. Just made some research and got that sites that doing that way are not using standart methods.

    Sorry for taking time, Umed

  88. jaisen Says:

    @Umed, You have to save the access tokens and then when the user comes back you can use them to make calls to twitter.

    The user only has to allow your application access ONE time. If you’re making them do that over and over, then you’re not properly saving the access token :)

  89. jaisen Says:

    @Rav, Make sure that the consumer key and secret are correct. If the oauth_token is blank then there’s something wrong with the OAuth authentication.

  90. Rahul Says:

    @jaisen i am having the same problem as @Umed… i am saving the two tokens in the database but how will i know which user is logging in to retrieve from the database.

    Could you please have a look at http://www.twittercontd.com/index_oauth_beta.php


  91. jaisen Says:

    @Rahul, unless you plan on using the “sign in with Twitter” feature then you’ll need to have a user database of your own.

    I think you’re looking for the ability for the user to sign into your site with Twitter, which is different from storing OAuth tokens for them in your own database.

    Anyone else care to weigh in on this? I don’t think I’m explaining it well :).

  92. Rahul Says:

    @jaisen sorry but I am still confused. I have the “sign in with Twitter” feature on my site (have a look at the link).

    So first time user logs in using twitter I get back 2 tokens from twitter for that user. Now I can perform changes for that user for the given session. The next time the same user comes back then he wont have to have “Deny or Allow” again but in my case he has to.

    The first time i will save the 2 tokens in my database (which I have). But the next time the same user comes back then what?

  93. Arik Says:

    @Jaisen, @Umed - don’t you have to use another url endpoint in order to skip the “allow application” screen after the user already authorized you?

  94. jaisen Says:

    @Rahul, the flow to “sign in with Twitter” is slightly different than the flow described here. @arik is correct in that you have to use a different endpoint (not covered in this blog post). Here is documentation for it: http://apiwiki.twitter.com/Sign-in-with-Twitter.

    Basically, once a user has allowed your application you can access the /oauth/authenticate endpoint (not mentioned here). This endpoint will check if the user is logged in to Twitter and whether or not they’ve granted your application access. Once the checks are completed then the user will be redirected to your site with the access token and token secret.

    Perhaps I should write a quick blog post on how to use EpiTwitter with the sign in with Twitter flow.

    Does that help clarify?

  95. Mike Says:

    @jaisen I’m having the same problem as @Vaibhav. I’m getting this in start.php after updating the key and secret.



  96. jaisen Says:

    @Mike or @Viabhav do either of you have a place where I can log in and have a look? Does the yapache error log show any messages?

    It’s hard for me to diagnose without taking a look at the problem myself.

  97. Rahul Says:

    @jaisen thank you for your help. But a quick blog post will be awesome. It will help me and also the others.

  98. pete Says:

    @Rahul etc if you want to use Twitter for login, and hence not store each user’s keys in your own db, then select that checkbox in your app’s settings.

    I then added the following to EpiOAuth.php:

      protected $authenticateUrl;
      public function getAuthenticationUrl()
        $retval = "{$this->authenticateUrl}?";
        $token = $this->getRequestToken();
        return $this->authenticateUrl . '?oauth_token=' . $token->oauth_token;

    and the following to EpiTwitter.php:

      protected $authenticateUrl = 'http://twitter.com/oauth/authenticate';

    you can then use:


    to point your users to the login workflow, rather than always sending them to the allow screen.

  99. phil davis Says:

    Please forgive me for asking this question. But I’ve figured out who to use the api to write direct messages and it works like a charm. What I can’t figure out or find is the api feature that lets me post public tweets for a user that has connected to my application. Can somebody point me to this in the documentation or tell me if it exist at all?

    Thanks phil

  100. jaisen Says:

    @pete, feel free to fork the repository at github and make a pull request for me to merge in your changes into the master branch.

    @phil, to post to a user’s status you need to use that user’s token and token secret when creating the EpiTwitter object (or use setToken if already created). Then all calls will be made on behalf of that user, including ones to update status.

  101. jaisen Says:

    Added “Sign in with Twitter” support and wrote a blog post about it. http://www.jaisenmathai.com/blog/2009/04/30/letting-your-users-sign-in-with-twitter-with-oauth/

    Working example: http://www.jaisenmathai.com/sign_in_with_twitter/

  102. phil davis Says:

    @jaisen, thanks again. I apologize. Works like a charm.

    The hacker in me - jumped in and started doing things without reading the documentation. My Bad


  103. Rahul Says:

    Thanks a lot works like a charm

  104. mlg Says:

    Sorry, I feel really dumb, but I can’t figure out how to allow status updates using your library. Everything worked perfect as far as logging in and saving tokens with cookies, etc.

  105. Sam Says:

    I use

    $post_tweet = "Heres the test";
    // update the status
    $update_status = $twitterObj->post_statusesUpdate(array('status' => $post_tweet));
    // get the ID of the tweet just sent
    $tweet_id = $update_status->response['id'];
  106. Gopu Says:

    i am having an issue with the
    get_friendshipsExist() return values. i dont seem to get a correct reponse.

    $checkfollow =$twitterObj->get_friendshipsExists(array('user_a'=>$twitterInfo2->screen_name,'user_b'=>$st2[1]));

    pls help with a correct method for getting the boolean response

  107. jaisen Says:

    @Gopu, I fixed the issue you were having and committed to github. $res->response always contains the json decoded value. That’s what you’ll want to check if it’s true or false.

    Thanks for reporting the bug.

  108. david Says:

    So after evaluating Twitter PHP Libraries for a project I’m working on, I really like EpiTwitter. The major problem I see going forward is OAuth. My project is a mobile website, and from first glance OAuth doesn’t seem feasible from a mobile browser. Is this one of the user cases for basic authentication they are waiting to solve before removing basic auth?

    Any advice on a mobile browser approach to OAuth would be appreciated.

    (I also think at this point EpiTwitter could benefit from a forum).

  109. Thong Tran Says:

    Thanks for the tutorial, I were developing a Twitter application for Joomla and it’s really helpful.

  110. michael Says:

    Hey guys,

    is anybody else having this problem? I have two apps registered at Twitter. Both are working fine with OAuth. I can access (read/write) data from Twitter.

    While the first app shows “from source” correctly, the second app doesnt.

    Instead of “from source” it shows “from web”.

    Maybe a Twitter bug? What do you think?

    Best wishes,

  111. Hiren Says:

    Hello All,

    I have set up the library code but in start.php it redirects to “http://twitter.com/oauth/authorize?oauth_token=”

    Over here the oauth_token is missing.

    Can anyone please help how to solve it?

  112. Shaikh Sonny Aman Says:


    is it possible to avoid registration step?

    Can anyone answer if the following is possible:

    1. On a site user may tweet which article they are reading by checking an option(a checkboc).

    2. will just fill in the tweeter username ( and password if neccessary, i don’t know if it is mandatory)

    3. then onward, the site will tweet what topic the user is reading now with the application name like

    “reading …..” 1hour ago from MY_SITE_APP

    4. The user should not be taken to twitter site to approve the application.

    is it possible or the must have to taken to the registration page ?

  113. michael Says:

    @Shaikh Sonny Aman:

    What you are planning isnt possible.

    With OAuth the user is always redirected to twitter.com for approval.
    >> “reading …..” 1hour ago from MY_SITE_APP
    Only possible with OAuth authentication.

    If you dont want to use OAuth, you can authenticate the user with his screen name and password. In this case, the user is not redirected to twitter.com.


  114. Shaikh Sonny Aman Says:

    Thank you very much for your reply and so quickly!

    All the best!


  115. jaisen Says:

    @michael, that seems like it would be an issue on Twitter’s end. I know it’s come up on the Twitter Development Talk group before.

    @hiren, did you update secret.php with your consumer key and secret?

  116. Hiren Says:

    @jaisen, Yes I have updated the secret.php

  117. jaisen Says:

    @hiren, make sure you’re running php 5.2 or higher. If you still have problems then feel free to send me the files you’re working with and I’ll have a look.

  118. Hiren Says:

    @jaisen, oh.. its 5.1.4.. do I have to upgrade it to 5.2 or higher?

  119. jaisen Says:

    @hiren, you’ll definitely need the json_* functions. They’re available for 5.1.4 as a pecl extension, or you can use the PEAR JSON_Services library and create your own json_* functions which wrap theirs.

    If you can upgrade to 5.2 without any problems, it might be worthwhile anyways :).

  120. Colleen Says:

    Hi, I need to do an operation which is pretty hard on twitter’s servers. In the past when I tested this with basic auth I would hit twitter’s limit and be blocked for an hour. So what I plan is to throttle the requests myself by building a queue and then a cron job that will issue the requests slowly enough for me not to piss off twitter. I guess I would have to have the tokens saved with the queued item. (Right now I am just cookie-ing them to the user but the user and his browser won’t be there when this cron job kicks in. ) I hoped to avoid a database for this little twick. Has anyone done anything like this and is there any security concern?

  121. jaisen Says:

    @Colleen, storing the tokens in your database is less of a security risk than storing passwords. In order to make use of the tokens you need the consumer key and secret. However, keep them safe!

    You can request to be whitelisted so you don’t keep hitting the limits and getting blocked. http://apiwiki.twitter.com/FAQ#IkeephittingtheratelimitHowdoIgetmorerequestsperhour

  122. Colleen Says:

    Yes indeed. I have the consumer key and secret those are constant as far as I’m concerned so they are configuration items. Oh looks like a liteweight SQL database.

    Thanks for the link on whitelisting. I thought you had to pass some kind of test to get whitelisted.

  123. Hiren Says:

    @jaisen, thanks for the reply and its really helpful. Now the further problem is, how to use the Post Method?

    I just want to have the two textboxes on my form (ie. username and password) and then I want to submit it. Is that possible?


  124. jaisen Says:

    @Hiren, if the username/password fields you’re talking about are for their Twitter credentials - then you won’t need those. The point of OAuth is so you don’t have to collect them from your users.

    For more information see this blog post: http://www.hueniverse.com/hueniverse/2008/10/beginners-gui-1.html

  125. dan Says:

    I’m trying to read a users timeline without being locked in, and I always get an error of “Invalid expired token”. Seems like I have to be authorized to read a users timeline (which is not protected), but the API documentations says:

    Requires Authentication (about authentication):

    true, if requesting a protected user’s timeline

    Am I doing something wrong?

  126. alon Says:

    i got an issue.

    $consumer_key = TwitterConsumer::key();
    $consumer_secret = TwitterConsumer::secret();
    $twitterObj = new EpiTwitter($consumer_key, $consumer_secret, USER_TOKEN, USER_SECRET_TOKEN);
    $userInfo = $twitterObj->get_accountVerify_credentials();
    $timeline = $twitterObj->post_favoritesCreate(array('id' => $id));

    when i try the above. it responds in

    {”request”:”\/favorites\/create.json”,”error”:”This method requires a GET.”}

    when i change the post_ to get_ i get

    {”request”:”\/favorites\/create.json?id=1472669360″,”error”:”Invalid \/ used nonce”}

    what todo?

  127. alon Says:

    btw, their api states the favorites/create requires POST. so its a tad bizarre.

  128. Arik Says:

    Alon - have you tried the following:

    $method = "post_favoritesCreate{$id}";
    $timeline = $twitterObj->$method();


  129. Arik Says:

    Actually maybe you need to add a ‘_’ somewhere there, but my point was that id isn’t a parameter for this API call, but part of the url…

  130. dan Says:

    @alon: have you tried something like this:

    $twitterObj->{'post_favoritesCreate'.$id}(array('id' => $id));
  131. alon Says:

    Arik. you rock!

    $method = “post_favoritesCreate{$id}”;
    $timeline = $twitterObj->$method();


  132. phil davis Says:

    I’ve can do other things with library but

    $twitterObjforSend = new  EpiTwitter($consumer_key, $consumer_secret);
    $ratelimitstatus = $twitterObjforSend->get_accountRate_limit_status();
    $rl_response = $ratelimitstatus->response;

    This tells me
    Failed to validate oauth signature or token

    What could I be missing?


  133. Sam Says:

    Hey dude. I’m having probelms calling the following:

    $get_friends = $twitterObj->get_friendsIds(array('id' => $_SESSION['my_twitter_id']));

    $get_friends->responseText gives me the Twitter Error page (”Something is technically wrong.”)

    Wondering if you can call the get_FriendsIds without any problems?


  134. jaisen Says:

    Several of you had asked about uploading profile/background images. I’ve added image support and committed it to a separate branch on GitHub.

    It’s currently at: http://github.com/jmathai/twitter-async/tree/multipart and docs are available as well: http://wiki.github.com/jmathai/twitter-async#multipart.

    I have two unit tests for it but would like more usage before I merge it into master. Let me know if you get a chance to try it out.

  135. @aloncarmel2k Says:

    im checking it now jaisen, thanks for the quick update ! :) you rock.

  136. nishant Says:

    hey.. twitter has put back callback url support in oauth. Can we use it with your api.

  137. nishant Says:

    thanks! the background image uploading worked perfectly at my server. Thanks.

  138. nishant Says:

    How do I specify tiled or not in this function?

    $twitterObj->post_accountUpdate_profile_image(array('@image' => '@/tmp/myfile.jpg'));
  139. @aloncarmel2k Says:

    just an update. jaisen it works great. uploaded picture works fine. Only issue is that twitter has problems with updating the api with the correct image url. so after user uploads the picture the correct url updates only in the username.xml and not in .json.

    prevents us from deploying it to production.

  140. jaisen Says:

    @aloncarmel2k, thanks for the update. i’ve also noticed that uploading pngs returns a 200 response but does not update the image.

    @nishant, you should be able to do the following:

    $twitterObj->post_accountUpdate_profile_image(array('@image' => '@/tmp/myfile.jpg'), 'tile' => 'true');
  141. Patrick Curl Says:

    I’m running into an issue here. Here’s my code:

    $twitterInfo2= $twitterObj->get_accountVerify_credentials();
    $twit_id = $twitterInfo2->screen_name;
    echo "you are:$twit_id!";
    $exists = $twitterObj->get_friendshipsExists(array('user_a' => $twit_id, 'user_b' => 'patrickcurl'));
    echo $exists->responseText;

    The way twtfollow works is when you join it you follow 10 people - your sponsors, then you recruit people and they recruit people, etc… to get more followers on twitter.

    What I’m trying to do is
    IF follower already exists skip, else follow.

    Right now I’m just testing the If exists part of this and I’m getting an error:

    Warning: Invalid argument supplied for foreach() in /home/patrickc/public_html/twtfollow.com/test/oauth/EpiTwitter.php on line 105


    As you see it did work - but it threw an error too - do you know why this error is being thrown?

  142. Patrick Curl Says:

    Actually I think I fixed it -I got the latest versions of the twitter asynch files and now seems fixed.

  143. Patrick Curl Says:

    Now running into another issue…. How do I get the friendshipCreate post method to work?

    I’m trying this:

    $twitterObj->post_friendshipsCreate(array('screen_name' => 'problogger'));

    but it’s not working, any ideas?

  144. jaisen Says:

    @Patrick, Try passing in id instead of screen_name. The docs say screen_name is required but I believe that to be an error. It’s generally used for disambiguation. I added a couple unit tests to verify that the friendships* endpoints work.

    For reference: http://github.com/jmathai/twitter-async/commit/95ec403873fc8e789ecdbcfda5a55f05a6a55714

  145. nishant Says:

    I tested my application yesterday without any error. But today I am getting Invalid token error everytime. Do you have any idea what can be the issue.

  146. nishant Says:

    I solved the invalid token error. I am not sure how it got solved. :)

  147. Patrick Curl Says:

    ok, running into another problem - anyone know how I can check to see if someone’s account is protected - ie can’t be autofollowed by my script?
    I’m using

    	if ($twit_id === $s_spid5)
        	echo "skipping, this is you!";
        $exists = $twitterObj->get_friendshipsExists(array('user_a' => $twit_id, 'user_b' => $s_spid5));
     		echo "Already following @$s_spid5";
          } else
       	$create = $twitterObj->post_friendshipsCreate(array('id' => $s_spid5));
        echo "Successfully followed @$s_spid5";

    this checks if the twit_id and user are the same (mostly in testing)

    Checks if friendship already exists if it does skip it.

    Create Friendship if doesn’t exist.


    Fatal error: Uncaught exception ‘EpiOAuthException’ with message ‘{”request”:”\/friendships\/exists.json?user_a=patrickcurl&user_b=joyce_j”,”error”:”You do not have permission to retrieve following status for both specified users.”}’ in /home/patrickc/public_html/twtfollow.com/test/oauth/EpiOAuth.php:301 Stack trace: #0 /home/patrickc/public_html/twtfollow.com/test/oauth/EpiTwitter.php(123): EpiOAuthException::raise(’{”request”:”\/f…’, 403) #1 /home/patrickc/public_html/twtfollow.com/test/confirm.php(101): EpiTwitterJson->__get(’response’) #2 {main} thrown in /home/patrickc/public_html/twtfollow.com/test/oauth/EpiOAuth.php on line 301

  148. jaisen Says:

    @Patrick, I don’t believe there’s an api for that. You could catch the EpiOAuthException exception and ignore it.

    try {
      $exists = $twitterObj->get_friendshipsExists(array('user_a' => $twit_id, 'user_b' => $s_spid5));
      if($exists->response) {
        echo "Already following @$s_spid5";
      } else {
        $create = $twitterObj->post_friendshipsCreate(array('id' => $s_spid5));
        echo "Successfully followed @$s_spid5";
    } catch(EpiOAuthException $e) {
      echo "Don't have permission to do this";
  149. Patrick Curl Says:

    ok, thanks - maybe I should suggest it to Twitter that they add it.

  150. Patrick Curl Says:

    It may be just really late and my mind is fried from staring at the pc - but I’m wanting to make automated tasks like for instance sending an update every day for a certain user using cron jobs.

    Is that possible with oauth?

    Also isn’t oauth_token and oauth_token_secret supposed to be unique values relatiive to the twitter id- are these what I would pass to the cronjob to authenticate the user when doing automated tasks?

    I’ve registered 3 diff twitter ids on my app, and they all have the same token and secret token.

    I think I’m a little confused - but this is my first php app ever, so I’m entitled to some confusion…

    Any advice would be wonderful.

  151. Patrick Curl Says:

    Sorry to ask a million questions - but sometimes I’m noticing that I get this error during testing:

    Fatal error: Cannot redeclare class EpiCurl in /home/patrickc/public_html/twtfollow.com/oauth/EpiCurl.php on line 3

    If I go back, refresh the screen then try again it works fine…. any ideas?

    it’s on my logout page - I clear all the cookies, then I have the authenticate url for them to click to sign back in if they want to…

  152. phil davis Says:

    I call a function that looks like this

    function UpdateTwitterStatus($consumer_key, $consumer_secret, $ut, $uts,$statusmessagearr)
    $twitterObjforSend = new EpiTwitter($consumer_key, $consumer_secret, $ut, $uts);
    $userInfo = $twitterObjforSend->post_statusesUpdate($statusmessagearr);
    $statusresponse = $userInfo->response;
    return $statusresponse;


    Where $ut and $uts is the users token and users secret token respectively of the user that the status message is for.


  153. Patrick Curl Says:

    hey phil thanks!

  154. Patrick Curl Says:

    Anyone else getting an error like this?: Fatal error: Cannot redeclare class EpiCurl in /home/patrickc/public_html/twtfollow.com/oauth/EpiCurl.php on line 3

  155. jaisen Says:

    @Patrick, somehow you’re including the file more than once. It could be a circular reference or something which could be solved by an include_once. If include_once doesn’t work then try and track down how it might be included multiple times.

  156. @aloncarmel2k Says:

    @jaisen you should really stop helping people in comments and direct to somewhere more productive. :)

  157. Now on Twitter, too | Sven Welzel - www.svenwelzel.com - blog.sven.co.za Says:

    [...] are over at http://toys.lerdorf.com/archives/50-Using-pecloauth-to-post-to-Twitter.html and http://www.jaisenmathai.com/blog/2009/03/31/how-to-quickly-integrate-with-twitters-oauth-api-using-p... Still — [...]

  158. Letting your users “Sign In With Twitter” with OAuth :: Jaisen Mathai Says:

    [...] to sign into your site with their twitter username and password. I recently wrote a blog post on how to use Twitter’s OAuth API. This feature is a natural progression in allowing Twitter users to securely sign into your [...]

  159. 10 Twitter API Tutorials. « The Domage Says:

    [...] 9. How to quickly integrate with Twitter’s OAuth API using PHP [...]

  160. Integración de OAuth para aplicaciones basadas en Twitter | germix.net Says:

    [...] | jaisenmathai.com (en [...]

  161. Twitter oAuth - php.de Says:

    [...] oAuth Hallo, mithilfe dieses Tutorials (How to quickly integrate with Twitter’s OAuth API using PHP :: Jaisen Mathai) versuche ich es zu realisieren, dass meine Benutzer sich sofort oder später mit Twitter verbinden [...]

About this site:
This is my (Jaisen Mathai) personal site for potential employers who want to see my resume or portfolio. My ideal job would be to work as a Web developer on a large scale consumer website. My experience is in using PHP, MySQL, Ajax and JSON. I really enjoy creative brainstorming...taking a problem apart and narrowing 100 solutions down to the best one.

Thanks for stopping by. Be sure to drop me a line.