It has been fairly easy to provide OAuth services in your web application (see How to turn your Rails Site into an OAuth Provider), but to actually consume Twitter, FireEagle, my own Agree2 and other OAuth services has been a fairly manual affair.
There are great gems out there that wrap up the process for the above mentioned services. So it hasn’t been too hard to support one of them. But what to do if you want to support 5 different services today and more in the future?
I knew there should be some generic approach to handle the OAuth authorization process, but had not spent too much time thinking about it until we actually needed to consume external web services for Agree2.
Well I think I’ve cracked it in a a nice Dont Repeat Yourself fashion.
OAuth Consumer Generator
I have now added a oauth_consumer generator to the Rails OAuth Plugin.
The oauth_consumer generator creates a controller to manage the authentication flow between your application and any number of external OAuth secured applications that you wish to connect to.
To run it simply run:
This generates the OauthConsumerController as well as the ConsumerToken model.
OAuth Authentication Flow
For each service you support the consumer presents the following 2 urls:
To connect to a users twitter account just add a link somewhere to go to the first URL and the plugin takes care of the rest. The callback is used internally and you don’t really need to worry about it.
If you send the user back the first URL he/she will have the option of removing or reconnecting. A http DELETE at that URL will remove an existing token.
You can configure any amount of services to support by editing:
All configuration of applications is done in
Add entries to OAUTH_CREDENTIALS for all OAuth Applications you wish to connect to. Get this information by registering your application at the particular applications developer page. I decided to use Ruby rather than yaml here so heroku users can Config Values here.
For generic OAuth services you need to add key, secret and an options hash with information of which URLs to use. See OAuth::Consumer for valid values. For services with wrapper classess (I’ll get into those shortly) you only need to specify key and secret as a wrapper class handles the rest.
For every service you add here you get the before mentioned 2 urls. So to link to Agree2 in the above example have a user follow a link to http://yoursite.com/oauth_consumers/agree2.
Using the OAuth Services
Every time a user is linked to one of these services it creates a new ConsumerToken. It actually uses STI and I dynamically create a new Subclass of ConsumerToken for each service listed in OAUTH_CREDENTIALS.
Using the above example you get 3 new classes:
This makes it easy to use from your user object. Add the following in your user model:
has_one :twitter_token,:class_name=>"TwitterToken", :dependent=>:destroy
has_one :fire_eagle,:class_name=>"FireEagleToken", :dependent=>:destroy
has_one :agree2,:class_name=>"Agree2Token", :dependent=>:destroy
has_one :hour_feed,:class_name=>"HourFeedToken", :dependent=>:destroy
Now you can access each of these directly in your own code. Each of these tokens implement a client method which will allow you to do stuff on the web service
By default this is an instance of OAuth::AccessToken but you can write wrapper classes to use a higher level library.
Wrapper tokens are classes written using to create a high level approach to working with a service such as Twitter. The plugin comes with wrapper classes for Twitter, Agree2 and FireEagle but it is fairly easy to write your own.
Here is an example using Twitter. It uses the Twitter Gem to provide a high level api:
current_user.twitter.client.update("Just had fantastic Jerk Pork on Boston Beach. Need beer!!")
This example uses FireEagle. It uses the Fireagle Gem to provide a high level api:
Creating your own wrapper tokens
If you have a service in CONSUMER_CREDENTIALS called :my_service just add a class to your models folder called MyServiceToken and it will be used instead of the auto generated one. In this example we are imagining a gem called ‘myservice’ that wraps around the web services actual api.
# Use a gem to do the heavy stuff
class MyServiceToken < ConsumerToken
# override self.consumer so we don't have to specify url's in options
# overide client to return a high level client object
@client||=MyService::Client.new( MyServiceToken.consumer.key,MyServiceToken.consumer.secret, token, secret)
# optionally add various often used methods here
If there isn’t a wrapper gem for the service you want to use. You can always add methods to MyServiceToken to do the parsing etc.
I hope this will get you started implementing OAuth. There no longer is an excuse not to.
Do you need advise or help with implementing OAuth in your Rails application?
I am available as a consultant and would be glad to help your company out. Whether you need help in developing an OAuth strategy or in practical hands on implementation help. Send me an email at [email protected] to let me know what you need help with and I can give you an estimate and my rate.