Wednesday, October 13, 2010

Twitter OAuth CodeIgniter Library, That was easy.

After spending months scratching my head and wondering if OAuth even works at all. I was able to crank out a library that will do OAuth for twitter in about 2 hrs. Yeah you are right I probably should have been actually doing my job but this is way more fun. It also gave me the opportunity to revisit my google OAuth library and fix the issues it had with HMAC signing.

Basically HMAC-SHA1 signing was impossible in the old google library, so I fixed that and it should still work the same if you are using RSA so don't worry about updating. If you want HMAC though you will need to jump through a few more hoops (nothing too serious) mainly involving keeping and using a token_secret value. I outline everything in the CI wiki if you are interested in how to use it and how it works.

Anyway back to the library I just finished. This library works pretty much the same exact way as the google library the only difference is twitter only lets you use HMAC signing. This means that you need to maintain a token secret value. Not a huge deal but one more thing to keep track of. If you want a more technical look at the implementation check out the CI wiki post I made here

Otherwise if you would rather just download the file you can get it from my dropbox account:
http://dl.dropbox.com/u/13081549/twitter_oauth.php

You also need the oauth_helper I wrote you can get it from dropbox here:
http://dl.dropbox.com/u/13081549/oauth_helper.php
If you want to see what it does then visit the wiki page here

Using this library is very similar to using the google oauth library here is an example:
function request_token()
{
  $params = array('key'=>'CONSUMER_KEY', 'secret'=>'CONSUMER_SECRET');
  $this->load->library('twitter_oauth', $params);
  $response = $this->twitter_oauth->get_request_token(site_url("site/access_token"));
  $this->session->set_userdata('token_secret', $response['token_secret']);
  redirect($response['redirect']);
}

function access_token()
{
  $params = array('key'=>'CONSUMER_KEY', 'secret'=>'CONSUMER_SECRET');
  $this->load->library('twitter_oauth', $params);
  $response = $this->twitter_oauth->get_access_token(false, $this->session->userdata('token_secret'));
  $this->_store_in_db($response);
}
The response array returned from the get_access_token call contains the access token, the access token secret, the twitter user id, and twitter screen name. You can do what you want with the last two values but you need to store the access token and token secret as these are how you authenticate with twitter.

[EDIT]
It was pointed out to me that once you have an OAuth access token it isn't exactly clear what you do with it. The OAuth portion of your API requests goes in the Authorization section of the header. The oauth_helper provides a nice function that will create the desired Authorization section.

$access = array('oauth_token'=>urlencode($this->session->userdata('oauth_token')), 'oauth_token_secret'=>urlencode($this->session->userdata('oauth_token_secret')));
$extra = array('status'=>rawurlencode('Tweeting from my API'));
$authhdr = get_auth_header('http://api.twitter.com/1/statuses/update.json', 'CONSUMER KEY', 'CONSUMER SECRET', array_merge($access, $extra), 'POST', OAUTH_ALGORITHMS::HMAC_SHA1);

The rest of the header is up to you. Make sure you include the values you are posting in the get_auth_header extra field, and that it is rawurlencoded.

[EDIT 2]
I also ran into an issue where I did not specify a callback when I registered the application with twitter. If you don't specify a callback, there is a bug with the registration process that will force your application to be set as a desktop application. If you are getting an index out of bounds exception when you make your first request make sure you have a callback set for your application on twitter.

19 comments:

  1. Maybe you should host it on github or bitbucket. I'm sure more people would be interested in this.

    ReplyDelete
  2. Doesn´t works on PHP 4.49 and Codeigniter 1.72

    ReplyDelete
  3. Yeah sorry its a PHP 5 only library. Guess I should stipulate that...

    ReplyDelete
  4. Authorization worked great! Thanks for this, I was wondering if you had any examples to make a call to the twitter API...??

    ReplyDelete
  5. Glad to hear it!

    No sorry I haven't actually written a twitter api library yet. Just the oauth stuff for now, but I will write one eventually since there really aren't any decent ones out there for CodeIgniter IMO.

    ReplyDelete
  6. Hi. The authentication works great. Can you please help me with, how should I make the API call now ?
    as i am new to this. Thaks

    ReplyDelete
  7. Have you visited http://dev.twitter.com ? That has all of the information on how to contact the API. You would then use that to develop your own library for contacting the Twitter API.

    This code was more meant as a jumping off point to start your own Twitter API Library. If you don't have much experience with writing that kind of code, I recommend downloading an actual Twitter API library. There are several available, just google "CodeIgniter Twitter API"

    ReplyDelete
  8. Hi
    thanks for your Twitter OAuth CodeIgniter Library
    i use it in my project
    i have a question and hope you can help me

    i tried to update a new message
    (https://api.twitter.com/1/statuses/update.json)

    by curl like this
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch,CURLOPT_POSTFIELDS,"status=test");

    but server return the error msg

    public 'error' => string 'Client must provide a 'status' parameter with a value.' (length=54)
    public 'request' => string '/1/statuses/update.json' (length=23)

    could you help me?

    thanks

    ReplyDelete
  9. Unfortunately I am not very familiar with the twitter API this library is only meant to give you access to the API as an authenticated user.

    ReplyDelete
  10. Jim, library works great for all kinds of OAuth APIs. However there's no information on how to create the proper OAuth signature once you have the access token information in CI Session variables. A quick tutorial would be nice. I've been able to set up requests, but they keep failing because the signature is not correct.

    ReplyDelete
  11. Oh, you're right, I never thought about that. I will do it right now. Thanks.

    ReplyDelete
  12. Hi,
    I'm trying to implement the request_token method and the acces_token...
    The request method works fine but after I authorize the application twitter redirect me to the acces_token method.
    But I have 2 requests. The first request look like:

    http://localhost:8888/begood/index.php/dashboard/access_token?oauth_token=XXXXXXXXXXXX&oauth_verifier=XXXXXXXXXXXX
    I get a 302 error and then I'm redirect to http://localhost:8888/begood/index.php/dashboard/access_token

    I think that codeigniter reactor doesn't accept query strings and this is the main reason because I'm redirected.

    Do you know how to solve it?

    Thanks in advance

    ReplyDelete
  13. I'm sorry but I am not really sure what you are trying to do.

    After you approve your application on twitter's site you are supposed to be redirected to your controllers access method (that completes the final step).

    CodeIgniter reactor does allow query string parameters but even if it didn't the API should still be able to get the query string values.

    To clarify the 3 step oauth process.

    1) The api contacts twitter and gets a request key and secret, then create a URL that will redirect to twitter.

    2) You redirect to twitter to approve the application.

    3) Twitter redirects back to your controllers access method, and provides an access token and access token secret. The library will get those values and return them to you.

    ReplyDelete
  14. I know the twitter flow, let me explain better...

    When twitter redirects me to my controller acces method I get and error 302 and I'm redirect to the same method without query parameters.
    Then I get this:

    Array ( [ \"1.0\" encoding=\"UTF-8\"?> Invalid / expired Token /oauth/access_token );

    Do you think that is necessary enable query strings?
    I'm using Codeigniter 2.0.2.

    ReplyDelete
  15. You can try that. I'm really not sure why your application would be 302 redirecting.

    Have you tried going to the access page directly and seeing what that does? (with and without query string values) Maybe there is an htaccess issue?

    The library should work without the query string being enabled (it was originally designed for 1.7.2 where query string was not available) It does this by parsing the $_SERVER['REQUEST_URI'] value which will always have the full uri including query string of a page.

    I don't think this has anything to do with either twitter or the library. From your descriptions it seems that your application is not configured for query string in some way.

    Could you post your request and access methods? That will help me debug. (Unless they are exactly the same as abo

    ReplyDelete
  16. Hi,

    I'm trying to fix this enabling query parameters.

    The error 302 doesn't appear but now the url that twitter redirects has a "?". The url that I get:
    http://localhost:8888/Marnews/?dashboard/access_token

    I don't know why this "?" is appearing. My oauth_callback is :
    http://localhost:8888/Marnews/dashboard/access_token/

    Do you undestand it? I don't!!!! Something makes no sense here!! :)

    ReplyDelete
  17. so

    http://localhost:8888/Marnews/dashboard/access_token/

    is the URL you are passing into the libraries request method right? If so, try removing that trailing slash, maybe that is confusing twitter and making it send that weird redirect.

    Is "Marnews" the name of your root CI folder, or is that the controller you are attempting to contact.

    Can you post your request and access controller methods that would help me pin point what the problem might be.

    ReplyDelete
  18. Hi Jim,

    I've fixed the problem. I changed this settings in config.php: $config['enable_query_strings'] = TRUE;
    $config['uri_protocol'] = 'QUERY_STRING';

    And now all works fine :)
    I think that this problem is only with CI 2.0.2...
    Thank for all man..

    ReplyDelete
  19. Regarding Anonymous' question some months back, you need to do array('status' => 'test') instead of 'status=test' and make sure the Content-Type header is multipart/form-data (although I'm sure that's been figured out by now).

    ReplyDelete