front and back-end web development, Leeds, UK


Richard's Blog - Design, coding and life in Japan

Richard

Using OAuth in Lithium

Using OAuth in Lithium to login your users to Facebook, Twitter, Google and Others

OAuthThe OAuth protocol is a fantastic way to login to remote services and websites. Unfortunately the spec is different in OAuth 1.0 and the yet un-solidified 2.0, the implementation is also different across different services. At the moment this is a bit of a goose chase, but libraries like li3_oauth can help!

I had played around with the Facebook PHP-SDK in Tom Maiaroto's Lithium plugin li3_facebook. Although this works fine to connect to the API. There is a lot of magic going on - especially when using the Javascript API, which is too hard to feel in control of. I like to be in control and calling the shots! I also want to have users have the option to login to other services under the same umbrella. Working directly with OAuth is what I wanted to do. Of course I was doing this in Lithium because it is clearly the best PHP Framework!

First step: Download Gwoo's li3_oath plugin

The only bummer here is that so far it is only OAuth 1.0 compatible. Both Facebook and Google are using OAuth 2.0. Although the 1.0 protocol is far more complicated and takes a lot of hassle to send all those 'Authorization' headers, so thanks Gwoo for doing all the initial hard work for me.

Second step: Fork and refactor plugin

To get twitter api working with the plugin required a few header options changed somewhat. So parameters like 'oauth_callback' needed to be added.

In order to get OAuth 1.0 and 2.0 running along side each other I created my own fork of oauth. I straight away cloned and simplified the Oauth Service class for version 2 as Oauth2. Because li3_oath client requests went through a single Consumer model I needed to re-factor the odd method into the service class itself where the protocols were different. I moved the extracted li3_oath\models\Consumer::token() method to li3_oath\extensions\service\Oauth::token() and also created li3_oauth\extensions\service\Oauth2::token(), but using the same original method to call out to these service classes.

Original li3_oath\models\Consumer::token()

public static function token($type, array $options = array()) {
    $defaults = array('method' => 'POST', 'oauth_signature_method' => 'HMAC-SHA1');
    $options += $defaults;
    return static::$_service->send($options['method'], $type, array(), $options);
}

New li3_oath\models\Consumer::token()

public static function token($type, array $options = array()) {
	return static::$_service->token($type, $options);
}

li3_oath\extensions\service\Oauth::token()

public function token($type, array $options = array()) {
	$defaults = array('method' => 'POST', 'oauth_signature_method' => 'HMAC-SHA1');
	$options += $defaults;
	eturn $this->send($options['method'], $type, array(), $options);
}

li3_oath\extensions\service\Oauth2::token()

public function token($type, array $options = array()) {
	$defaults = array('params' => array(
		'client_id', 'client_secret'
	));
	$options = array_merge_recursive($options, $defaults);
	$this->_parseParams($options);
	$url = $this->_config[$type];
	$result = parent::get($url, $options['params']);
	return $result;
}

Third Step: Create Tweet and Facebook Controllers

I could then go ahead and build my samples that were needed for Twitter and Facebook. You can go ahead and checkout these controllers and use them as a base for your own service based activities. I was able to use many of these actions inside a Lithium 'Auth' adapter to make my standard authorization mechanism to take advantage of them.

Forth Step: Re-factor further to turn this into an adaptable service client - Yet to do!

Although the original li3_oath code was well written and the current setup is usable. Because many of these actions are standardized but there are many ways to create the same action the use of adapters in Lithium suits the job perfectly.

There is a strong reliance on controllers and models at the moment, which I would not usually associate with service based module. I would move much of the 'Consumer' model to an interface, creating implementations for both Oauth and Oauth2. I would then create Twitter, Google and Facebook adapters - these can then be overwritten or added to in your own applications, without needing to change the base classes. Then only the very bare minimum needs to be used in models or controllers. This will also mean that configuration options can be kept well away from any controllers which is not really the place for it.

This is what I am planning on hacking away further to improve the usability of this library - If Gwoo doesn't get angry at me!

Documentation, Server and Other Stuff 

When first picking up the plugin I was a little unsure of what it was meant to do. Putting a little effort into the documentation would have made this much easier to use. I think I should add to this when I get chance - unless I have any other takers?

There is also a server side to this library which I have not really done much more than have a brief look at. Long term being able to add OAuth service to your own website will make inter-site, inter-api and distributed authorization systems a breeze.

Recent Blog Posts