A growing number of APIs support OAuth, i.e. it is possible to give service A access to service B without giving B’s username/password to A. In this article I’m going to show you how to use OAuth-enabled APIs with CakePHP (and the OAuth consumer component I have written).
First, there are some preparations necessary, namely the download of the required files:
- Get the OAuth component and place its content in “app/controllers/components”
- Get the OAuth library and put it in “vendors/OAuth”
- Set the security level in app/config/core.php to “low” (thanks to Bryan Young for mentioning in the comments)
The next step is to register your application at the service provider (e.g. Yahoo’s Fire Eagle) to get consumer key and consumer secret. Those values are then stored in a class called FireEagleConsumer if we go on using Fire Eagle as example service provider in this article:
// app/controllers/components/oauth_consumers/fire_eagle_consumer.php
class FireEagleConsumer extends AbstractConsumer {
public function __construct() {
parent::__construct('THE KEY', 'THE SECRET');
}
}
This class is then used by the component to access consumer key and secret.
Using an OAuth-enabled API consists of four steps:
- Get RequestToken
- Authorize RequestToken
- Exchange RequestToken for AccessToken
- Access the API using the AccessToken
In the ideal case the first three steps are performed once. But it is also possible that for example the service provider expires the AccessToken after some time, and so those steps have to be repeated.
Anyway, let’s have a look at how those steps look in code. We start with getting the RequestToken:
// app/controller/oauth_consumer_example_controller.php
class OauthConsumerExampleController extends AppController {
public $uses = array();
public $components = array('OauthConsumer');
public function index() {
$requestToken = $this->OauthConsumer->getRequestToken('FireEagle', 'https://fireeagle.yahooapis.com/oauth/request_token');
$this->Session->write('requestToken', $requestToken);
}
}
The code is probably self-explanatory, we have to add the component to the $components array, and then we get the RequestToken from the specified url (while writing this I just realized it would make sense to move the url to the FireEagleConsumer class…).
The next step is simple: we have to redirect the user to the authorize page of the service provider:
// app/controller/oauth_consumer_example_controller.php
class OauthConsumerExampleController extends AppController {
public $uses = array();
public $components = array('OauthConsumer');
public function index() {
$requestToken = $this->OauthConsumer->getRequestToken('FireEagle', 'https://fireeagle.yahooapis.com/oauth/request_token');
$this->Session->write('requestToken', $requestToken);
$this->redirect('http://fireeagle.yahoo.net/oauth/authorize?oauth_token='.$requestToken->key);
}
}
After the RequestToken is authorized, we get redirected to a callback url we specified while registering the application. We can now exchange the authorized RequestToken for an AccessToken:
// app/controller/oauth_consumer_example_controller.php
class OauthConsumerExampleController extends AppController {
public $uses = array();
public $components = array('OauthConsumer');
...
public function callback() {
$requestToken = $this->Session->read('requestToken');
$accessToken = $this->OauthConsumer->getAccessToken('FireEagle', 'https://fireeagle.yahooapis.com/oauth/access_token', $requestToken);
}
}
In a real use case you would also save the data of the AccessToken (key and secret) to the database, so you don’t have to perform all those steps every time you want to call the API.
The last step is to call the API, in this example to get the latest location of the user:
// app/controller/oauth_consumer_example_controller.php
class OauthConsumerExampleController extends AppController {
public $uses = array();
public $components = array('OauthConsumer');
...
public function callback() {
$requestToken = $this->Session->read('requestToken');
$accessToken = $this->OauthConsumer->getAccessToken('FireEagle', 'https://fireeagle.yahooapis.com/oauth/access_token', $requestToken);
$data = $this->OauthConsumer->get('FireEagle', $accessToken->key, $accessToken->secret, 'https://fireeagle.yahooapis.com/api/0.1/user');
// do something with the data
}
}
That’s it. Feedback is welcome!
Update 2008-09-15: Slightly adapted for new version of the component.
Update 2009-01-14: Adding hint about security level.

This is great, thanks Daniel.
Just a few weeks ago I thought, that it would be really great if there was a OAuth Component in CakePHP.
I will try this one out as soon as i can.
Have you also experimented with enabling a cakePHP-app as a OAuth-provider? I tried but failed horribly ;-)
+1 to Andreas’s request CakePHP app as an OAuth provider would be great!
@Andreas, Tarique: Thanks for your comments!
Yes, I’m experimenting with enabling a CakePHP app to be an OAuth provider and I hope I can write about it soon ;-)
[...] first is a component for CakePHP for accessing services with OAuth called OAuth component for CakePHP (points for [...]
Daniel, thanks for the great OAuth tutorial. You may want to mention somewhere in your article that the security level in /config/core.php needs to be set to ‘low’ to make this work.
@Bryan: Thanks for the hint, I added your hint to the article!
Thanks for the great tutorial!
It worked just fine for Fire Eagle, but when I tried getting a request token from myspace, who also has OAuth for their applications, it returned a null $requesToken after calling getRequestToken() and passing in the proper parameters. Should the code be any different between providers?
@Justin: Did you use a network analyzer like Wireshark to analyze what’s going on? And do you use the correct HTTP method to request the request token?
I’ve been trying to set this up using plugins but seems like the oauth consumer cannot find the consumer files.
It throws an error on line 69 because it’s searching for the main app component folder.
Is this a handicap or am I doing something wrong?
Actually I changed line 59 to this
$CONSUMERS_PATH = dirname(__FILE__).DS.’oauth_consumers’.DS;
and it now works in the plugin except I’m having a null accessToken…
was it me :|
@Rui: The issue with not finding the consumer files is definitely a bug, I didn’t think about plugins at the time I developed it. I have to fix this.
Regarding the second issue, it is difficult to say what could be the problem. Did you use a tool like Wireshark to see what’s going on?
@cakebaker: If you change your line 59 to what it posted it will work.
The rest was me being lazy and not setting the security level on cake to low.
It seem to work ok now.
BTW why not post your component on github or something?
@Rui: Ok, the bug is now fixed. And I’m glad the other problem disappeared :)
The component is already available on github: http://github.com/cakebaker/oauth-consumer-component/. However, I didn’t have linked to it yet ;-)
@cakebaker: Tip, how about another article using Gdata? :)
@Rui: Good idea, though I don’t have used Gdata yet ;-)
I know this article was written back in September but I just found it and am having problems. First, writing the requestToken Object to the Session is getting destroyed by Cake once the redirect has happened. Is anyone else having this issue? I am trying to do this with Twitter and I can get Twitter to allow my application but once it redirects to my callback url, there is no token to read, so I can’t get the access token. Any help would be really appreciated.
@Ryan: Thanks for your comment!
Hm, what’s the setting of “Security.level” in app/config/core.php? Can you set it to “medium” or “low”, and try again?
Hope that helps!
Security level is set to low. I have tried changing Session.start to false and manually creating my session but that didn’t seem to help. I have Session.save set to database, so I can see that it is writing the token to Session, but then it creates a new session once I return from Twitter.
@Ryan: You mention you set “Session.save” to “database”. Does it work if you keep the default value (“php”)?
No it didn’t work then either. I don’t know if that is tied into the cookies being saved as CAKEPHP and PHPSESSID, I haven’t tried that yet.
@Ryan: Hm, at the moment I don’t have any idea what could be the problem… I currently use it with Twitter in NoseRub, without any problem so far.
I’m running Cake 1.2.2.8120 and I’m getting the error:
Fatal error: Class ‘OAuthConsumer’ not found in (…)/controllers/components/oauth_consumers/abstract_consumer.php on line 40
Sorry, I just didn’t put the library into the vendors directory when I thought I had… Feel free to delete this and the last comment!
@psuedo: No problem, I hope it works now as expected!
Does anyone know how to import contacts from Gmail, yahoo hotmail using this?
The example is very basic but a good example to start off with.
Thanks
@Jerry: At least if the services you mention provide an OAuth-enabled API it should work in a similar way as shown in the example: you have to get an access token and with that access token you can then access the respective API. Or did you encounter a specific issue?
Hi David,
Iam trying to connect to google docs api using this component.. however, I get an error saying
“parameter_absent oauth_parameters_absent:scope ”
The code Im using is as follows:
Because of this I cannot seem to get past the first step of this tutorial ;)
Ever run across this?
thanks
Fixed… our server time was off.
@Keith: Good to hear you could fix the issue in the meantime :)
You don’t have an example of using a previously stored access token. This would be greatly appreciated as it is not clear to me at all how to do this, nor have I seen or heard of anyone doing this with a site like, let’s say Twitter. Is it possible, or are you just pointing out how to use a preexisting library of code? Because as actual solutions go, this one isn’t fully realized.
@J. Adam: Thanks for your comment!
Well, usually an access token is represented by a model, and so you retrieve it with something like $this->AccessToken->find(‘first’, some criteria); And with those data you can then call the respective API as shown in the article, simply replace $accessToken->key and $accessToken->secret with the data you got from your model.
Hope that helps!
cakebaker..thanks for another great article. Though I was hoping there would be a component to have a CakePHP app be an OAuth provider.. are you close to a solution for that one? :)
@kunal: Thanks for your comment!
Well, you can find an implementation of an OAuth provider in NoseRub (http://code.google.com/p/noserub), though it is a bit more than just a component: it consists of a component, two controllers and some models ;-)
However, I’m currently adapting it to OAuth 1.0a and so the code in the development branch is a bit in an undefined state… Maybe I should try to make this part of NoseRub more independent, so it can be used by others, or at least write an article about it.
thanks, if you could write an article on that, and perhaps if you get a chance to make a modular component out of it, that would be awesome.
Hum.. Haven’t touched this in a while.
Still having problems in using this in a plugin, but this time it’s not the same as before (thanks for using my #BUGFIX ;))
On line 75 of the oauth_consumer.php || return $consumerClass->getConsumer();
Throws me an exception “Fatal error: Class ‘OAuthConsumer’ not found”
Following the code, the getConsumer() method of the abstract_consumer.php returns || new OAuthConsumer($this->consumerKey, $this->consumerSecret);
I’m not getting it, any clues?! this worked before (I just downloaded the most recent code you had available)
Dumb ass… working late has these things.
I figured it out, it’s very simple. I was trying to use the /plugin/vendors/OAuth/OAuth.php and you script searches for the /app/vendors/OAuth/OAuth.php
I need to override this, any suggestions as for the better place to do it?
@Rui: I uploaded a new version which should fix this issue: http://code.42dh.com/oauth (please also check the changelog).
Nice dude,
I’m going to update my code asap and I’ll let you know how it all worked out.
for those who are trying to get auth or access tokens for YouTube BE-WARNED (ACHTUNG) do not include a callback parameter when you “getRequestToken” this is because YouTube does not return the “oauth_verifier” and you will also have to change a few lines of code in the OauthConsumerComponent::getAccessToken() – just introduce a simple check to include ‘oauth_verifier’ only when the value is set.
YouTube does not seem to have aligned itself to OAuth 1.0a and what’s more funny is that even if you specify oauth_version to be 1.0, it’s going to “treat” it as 1.0a if you include a callback url and will demand an oauth_verifier although it will not provide you one. May be they’ll fix this issue soon.
@SayB: You could try the previous version of the component, as it supported OAuth 1.0. But maybe it would make sense to re-add support for OAuth 1.0?
I try to use the vendors of OAuth, how to return the code. Please see the code.
but when I var_dump($requestToken); of line 12, it is NULL, why? Can anybody help me?Thx~
@HHuan: Hm, I don’t know why you specify the url to your “rs” action as the first parameter for the getRequestToken() method (and not the url to get a request token for Twitter, i.e. http://twitter.com/oauth/request_token )…
Anyway, if you want to use your rs() method to return a request token, then the method should look like:
Hope that helps!
Thx a lot, coz i am new to use OAuth, i misunderstood before, but in our country, we are rejected to view twitter, too bad…
By the way, is that linking to google is different from linking to twitter? Please help me.
@HHuan: Hm, I am not sure I understand your question. What do you try to accomplish? In the code I noticed two things: in the google() method you have to redirect to an “authorize” page at the end of the method. And the code below “below i dont know how to handle it” you have to use a Google url, you can’t post to twitter with an access token from Google.
Hope that helps a bit!
[...] This post was mentioned on Twitter by Benjamin Pearson, Benjamin Pearson. Benjamin Pearson said: @benjaminpearson It's basically built on this http://bit.ly/vnwlj [...]
Please help me! I use your OAuth component with google service but i have a problem. I don’t know why $requestToken is NULL !!! My code is:
bxukz+ 殶˦z-QzƢ%zm %y&Fz^笵:$zݺjkz+m+ '*'+zz+ m %y&@h,NhzGbwVrJު笵:$z{a-I,භv-NzGӚB{.Ƣ%zm %y&Fzq,N-Nand in oauth_consumer folder i have a file google_consumer.php :
rVj(W{.קvrШ˦znnX~ܶ*'r춻z{{--)lyI checked it and I realized that the request method in http_socket.php doesn’t work, It always return NULL. I don’t know why. Please help me.
oops, what ‘s wrong with my code :| ?
In google_consumer.php
In http_socket.php the code
It doesn’t work, $response is always NULL !!!
@Kakakatt: Your code looks correct. Did you check with a tool like Wireshark whether a request was performed? And is the OpenSSL extension activated in your php.ini?
Hope this helps!
I found the error.It occurs when I tried to receive the request token,
There was a oauth_callback_confirmed string flowing. It looks like this:
object(OAuthToken)#30 (2) { ["key"]=> string(30) "4/kJgZjbdAcEujx8acnVOyaPYJZKRa" ["secret"]=> string(54) "N4lAsT6qQnZahUTbRF1Cm66/&oauth_callback_confirmed=true" }Yep, you need to remove the call back string and then the problem will be solved
object(OAuthToken)#30 (2) { ["key"]=> string(30) "4/kJgZjbdAcEujx8acnVOyaPYJZKRa" ["secret"]=> string(54) "N4lAsT6qQnZahUTbRF1Cm66/" }But I have a other problem that OAuth can’t be used with picasa. Are there anyone want to help me ? Thanks
I found the error.It occurs when I tried to receive the request token,
There was a oauth_callback_confirmed string flowing. It looks like this:
object(OAuthToken)#30 (2) { ["key"]=> string(30) "4/kJgZjbdAcEujx8acnVOyaPYJZKRa" ["secret"]=> string(54) "N4lAsT6qQnZahUTbRF1Cm66/&oauth_callback_confirmed=true" }Yep, you need to remove the call back string and then the problem will be solved
object(OAuthToken)#30 (2) { ["key"]=> string(30) "4/kJgZjbdAcEujx8acnVOyaPYJZKRa" ["secret"]=> string(54) "N4lAsT6qQnZahUTbRF1Cm66/" }But I have a other problem that OAuth can’t be used with picasa. Are there anyone want to help me ? Thanks
@Kakakatt: Hm, I just tried it myself and it worked fine without removing the param. Do you use the latest version of the oauth component?
What is the problem with picasa? At least from this ticket http://code.google.com/p/gdata-issues/issues/detail?id=701 it seems like OAuth is supported by picasa.
May I read your code ? I have used Oauth component 2009-09-05 version.
The link you provided do not deal with the problem, it was just warning of mistake. I have read sources from Google API that: Picasa is just compatible with Auth http://code.google.com/apis/picasaweb/docs/1.0/developers_guide_php.html
@Kakakatt: Sure, here it is. The consumer class:
And the controller:
I hope this helps.
And regarding OAuth and Picasa: at least according to Google’s OAuth announcement Picasa should also be supported.
Would you know any reason why the callback would return NULL in a Google Chrome browser but work fine in FireFox and IE? So far I can’t figure it out.
The first error I get when using chrome is
Trying to get property of non-objectThe line it’s throwing the error on is:
$credentials = $consumer->get($accessToken->key, $accessToken->secret, 'http://twitter.com/account/verify_credentials.json');@CantonDog: Hm, I assume you get the error when accessing the key and secret properties of $accessToken, right? Did you check whether you got an access token back after calling the getAccessToken() method?
I’m not sure if this helps…
[...] are no available CakePHP components or plugins that implement an OAuth server (although there are these for doing client [...]
Hii, thanks for this great component.
Am facing the same problem as ryan and cantondog.
either requestToken is getting destroyed from the session, although I have set my security level to low.
@amjedonline: Hm, so it works with some browsers, but not with others? In which browsers do you encounter issues? On which platform are you? And which CakePHP version do you use?
Here on Linux with Cake v1.3.2 it works fine with FF 3.6.8 and Chrome 5.0.375.125 if the security level is set to “low”.