How to turn your rails site into an OAuth Provider 19

Posted by Pelle Mon, 26 Nov 2007 01:35:38 GMT

This has been updated on the Nov 27th 2007. Please read below if you have already installed it

OAuth is the great new standard allowing your users to use your application to talk to their accounts on other applications. I won’t go more into it here as it’s pretty well covered on the OAuth site.

I have created an OAuth Rails Plugin and an oauth gem which will help you to create both oauth providers and consumers.

Consumers and Providers

I will cover consumers in another post, but it’s probably a good idea to explain what the difference is:

A consumer is an application that uses another web applications data. For example for a mashup. It is mainly intended for web applications, but there is nothing to stop you from writing say a way cool Mac client in Cocoa as well.

A provider is a web application that the consumer wants to access.

The classic example is a photo printing site as a consumer and a photo site (like Flickr) as the provider.

Provider features

The plugin can generate an oauth provider that supports the following out of the box:

  • User can register their own applications to receive consumer key/secret pairs.
  • Provider supports standard best practises out of the box hmac-sha1 etc.
  • Users can manage and revoke tokens issued in their name
  • Easy before filter to provide oauth protection on your actions

Install the plugin

This plugin currently requires Rails 2. If someone would like to make it Rails 1.2 compatible. Please feel free to submit patches.

NEW First install the oauth gem:

sudo gem install oauth

Then install the plugin:

script/plugin install http://oauth-plugin.googlecode.com/svn/trunk/oauth_plugin

You also need an authentication plugin that is compatible with acts_as_authenticated, restful_authentication or restful_openid_authentication.

Lets create your provider

The generator is not very flexible at the moment. So it doesn’t really allow you to change names for models and controllers.

Type:

script/generate oauth_provider

This creates OauthController and a few different models.

Until I figure out how to do this automatically you need to enter the following into your routes.rb

map.oauth '/oauth',:controller=>'oauth',:action=>'index'
map.authorize '/oauth/authorize',:controller=>'oauth',:action=>'authorize'
map.request_token '/oauth/request_token',:controller=>'oauth',:action=>'request_token'
map.access_token '/oauth/access_token',:controller=>'oauth',:action=>'access_token'
map.test_request '/oauth/test_request',:controller=>'oauth',:action=>'test_request'

You also need to add a few associations to your user object:

has_many :client_applications
has_many :tokens, :class_name=>"OauthToken",:order=>"authorized_at desc",:include=>[:client_application]

Now run your migrations and start your server:

rake db:migrate
script/server

And your oauth provider is now up and running on http://localhost:3000/oauth to start registering a client application.

Protect your actions

I recommend that you think about what your users would want to provide access to and limit oauth for those only. For example in a CRUD controller you may think about if you want to let consumer applications do the create, update or delete actions. For your application this might make sense, but for others maybe not.

If you want to give oauth access to everything a registered user can do, just replace the filter you have in your controllers with:

before_filter :login_or_oauth_required

If you want to restrict consumers to the index and show methods of your controller do the following:

before_filter :login_required,:except=>[:show,:index]
before_filter :login_or_oauth_required,:only=>[:show,:index]

If you have an action you only want used via oauth:

before_filter :oauth_required

All of these places the tokens user in current_user as you would expect.

Please bear in mind this is still early days and their maybe some major bugs and or changes coming. But please help me test the code.

There are also 2 other implementations:

  • Choon Keat’s OAuth4R which is a rails plugin for both creating providers and consumers. Choon and I are talking about how we can merge things.
  • Blaine’s original OAuth. This is the original ruby library as used at Twitter. It is not very well documented at the time of writing and consists mainly of base ruby library instead of full Rails integration. Have a look at it, it may suit you.

If your company needs help getting your OAuth Strategy right or implementing OAuth in your application I’m available for consulting work pelle@stakeventures.com.

Create a simple NDA with zero legalese in no time at all and for free at our service Agree2.

Trackbacks

Use the following link to trackback from your own site:
http://stakeventures.com/articles/trackback/263

Comments

Leave a response

  1. Avatar
    choonkeat Mon Nov 26 03:20:17 +0000 2007

    Hi Pelle,

    Very happy the Ruby/Rails side of things are finally progressing!

    Unfortunately, for the routes, the only support for generators seem to only generate restful routes . You will need to copy-paste the function and customize locally.

  2. Avatar
    sergiu Mon Nov 26 08:20:14 +0000 2007

    how is OAuth different than OpenID?

  3. Avatar
    Pelle Mon Nov 26 18:47:15 +0000 2007

    Choonkeat, I feared as much. Maybe I’ll do a patch to rails. I’ve already got a patch through in that area.

  4. Avatar
    Pelle Mon Nov 26 18:50:19 +0000 2007

    Sergiu,

    OpenID and OAuth er complimentary technologies that server 2 very different purposes.

    OpenID is used for users to identify themselves and login interactively to various web services. So Browser to Server.

    OAuth is used by a user to give Server A permissions to use the users data on Server B. So Delegated Server to Server.

    I know it can be a bit confusing. It took me a while to completely understand it.

  5. Avatar
    sergiu Tue Nov 27 07:40:29 +0000 2007

    I’ve read a few examples about OAuth so now it’s much clear. It’s great having it as a Rails plugin, thanks for doing this.

  6. Avatar
    jk Mon Feb 04 02:37:41 +0000 2008

    May I ask what is the time frame on the consumer generator or tutorial?

  7. Avatar
    Shane V. Fri Feb 08 02:56:45 +0000 2008

    Eagerly awaiting the Consumer post… :) Great gem btw.

  8. Avatar
    Pelle Fri Feb 08 03:14:14 +0000 2008

    I guess, I’ll have to write it then ;-)

    If you want to get started have a look at the OAuth Gem RDoc, which apparently isn’t linked from the main site.

    The only 3 classes you need to worry about are:

    • OAuth::Consumer
    • OAuth::RequestToken
    • OAuth::AccessToken

    The basic flow is that you configure an instance of OAuth::Consumer with the details the service provider (say Twitter or Agree2 gives you).

    (Hint Agree2 actually generates a code snippet for you)

    I digress…

    <pre><code>@consumer=OAuth::Consumer.new “key”,”secret”,{:site=>”https://agree2.com”} @request_token=@consumer.get_request_token redirect_to @request_token.authentication_url @access_token=@request_token.getAccessToken

    @people=@access_token.get(”/users.xml”)</code></pre>

    The plan is to create a generator in the plugin that creates a controller and a set of models to manage this whole process with your users.

    I am also in touch with Daniel who is working on integrating this into ActiveResource.

  9. Avatar
    Corey Thu Jul 17 10:33:47 +0000 2008

    I am a Rails Noob, so please pardon me if I ask any obvious questions. With that said…after I perform the rake db:migrate towards the top of this ‘tutorial’, and I try to do the next step: “And your oauth provider is now up and running on http://localhost:3000/oauth to start registering a client application.”, I am getting an “undefined method ‘login_required’ for #OauthController….”

    Am I missing something? Any ideas to help me along would be much appreciated!

  10. Avatar
    Pelle Thu Jul 17 16:29:06 +0000 2008

    It sounds like you’re missing one of the authentication plugins above.

    My recommendation is restful_authentication

  11. Avatar
    Dave Mon Aug 04 14:13:37 +0000 2008

    HI Pelle,

    Another newbie. Getting the same error as Corey. I have the restful_authentication plugin installed/ Do I need to run ”./script/generate authenticated …” before I run your generator?

  12. Avatar
    Pelle Braendgaard Tue Aug 05 00:33:37 +0000 2008

    Dave, Yes you’re right you need to fully install the plugin and generate it’s code first.

    Pelle

  13. Avatar
    Santosh Mon Sep 08 09:30:50 +0000 2008

    your oauth provider is now up and running on http://localhost:3000/oauth to start registering a client application.”, I am getting an "undefined local variable or method `current_user’ for #<OauthController:0×4839b8c>
    " error.

    altough i am getting the registration screen for the url http://localhost:3000/oauth/new. but getting the same error on hitting the create button.

    how are we going to initialize current_user. do we need to make the authentication module of our own?

  14. Avatar
    Pelle Braendgaard Mon Sep 08 09:45:14 +0000 2008

    Santosh,
    You need to fully install one of the authentication plugins first as mentioned above.

  15. Avatar
    Santosh Wed Sep 10 06:18:41 +0000 2008

    i installed the restful_authentication pluggin, and folled the steps stated by you. now on firing the url http://localhost:3000/oauth, i am getting this error “undefined method `login_required’ for #<OauthController:0×487d7d8>”

  16. Avatar
    Tyler Sun Oct 26 00:42:43 +0000 2008

    Great resource, I added it to the Netflix Resource center at http://netflixapi.com

  17. Avatar
    puran Fri Dec 05 11:00:31 +0000 2008

    Hi,

    I am new to this and getting below errro after follow up with all the stpes mentioned above, but still tillte bit doubt for :

    *********************
    You also need to add a few associations to your user object:

    has_many :client_applications
    has_many :tokens, :class_name=>“OauthToken”,:order=>“authorized_at desc”,:include=>[:client_application]
    ****************************

    In which file I need to add these lines.

    Getting below error when browsing:
    **********************

    NoMethodError in OauthController#login
    undefined method `login_required’ for #<OauthController:0×47f552c>

    ************************

    Please help me out

  18. Avatar
    masone Wed Dec 31 07:26:41 +0000 2008

    I think the link for starting registering client applications should be (instead of /oauth):
    http://localhost:3000/oauth_clients

    To do this I added the corresponding route:
    map.resources :oauth_clients

  19. Avatar
    Steven Chau Sun Jan 04 06:34:59 +0000 2009

    If using restful-authentication plugin, after adding ‘include AuthenticatedSystem’ to the application.rb did the missing errors and variables stopped.

    I agree with @masone, http://localhost:3000/oauth_clients presents a working page, rather than using /oauth url. Still trying to figure out that last part.

Comments

(sorry javascript required)