How to turn your rails site into an OAuth Provider

Posted by Pelle November 26th, 2007 47 comments edit

This has been updated on July 21st, 2009 to reflect all the latest changes*

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.

First install the oauth gem:

sudo gem install oauth

The plugin can now be installed as an gem from github, which is the easiest way to keep it up to date.

sudo gem install oauth-plugin

You should add the following in the gem dependency section of environment.rb

config.gem "oauth"
config.gem "oauth-plugin"

Alternatively you can install it in vendors/plugin:

script/plugin install git://github.com/pelle/oauth-plugin.git

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 creates 2 controllers a set of models and views.

Type:

script/generate oauth_provider

You now 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_clients 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.

If your company needs help getting your OAuth Strategy right or implementing OAuth in your application I’m available for consulting work [email protected].

Posted November 26th, 2007 under:
Comments
choonkeat@gmail.com
choonkeat November 26th, 2007 destroy

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.

sergiutruta@gmail.com
sergiu November 26th, 2007 destroy

how is OAuth different than OpenID?

pelle@stakeventures.com
Pelle November 26th, 2007 destroy

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

pelle@stakeventures.com
Pelle November 26th, 2007 destroy

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.

sergiutruta@gmail.com
sergiu November 27th, 2007 destroy

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.

jk February 4th, 2008 destroy

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

shanev@gmail.com
Shane V. February 8th, 2008 destroy

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

pelle@stakeventures.com
Pelle February 8th, 2008 destroy

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=&gt;"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.

mctenold@gmail.com
Corey July 17th, 2008 destroy

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!

pelle@stakeventures.com
Pelle July 17th, 2008 destroy

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

My recommendation is restful_authentication

dave.seidel@gmail.com
Dave August 4th, 2008 destroy

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?

pelle@stakeventures.com
Pelle Braendgaard August 5th, 2008 destroy

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

Pelle

vermask7@gmail.com
Santosh September 8th, 2008 destroy

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?

pelleb@gmail.com
Pelle Braendgaard September 8th, 2008 destroy

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

vermask7@gmail.com
Santosh September 10th, 2008 destroy

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>”

TylerQC@gmail.com
Tyler October 26th, 2008 destroy

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

pooran.joshi@gmail.com
puran December 5th, 2008 destroy

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

ema@rh-productions.ch
masone December 31st, 2008 destroy

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

steven.chau@mac.com
Steven Chau January 4th, 2009 destroy

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.

kannaa.ram@gmail.com
Kannan R July 9th, 2009 destroy

Has anyone tried 2-legged OAuth?

If so can you please let me know if it generates the signatures properly?
i’ve been trying to get the 2-legged OAuth working, but the client and provider generates different signatures.

i tried with other clients as well… still no help yet.

@ clients end
?oauth_nonce=WrGjXcZheoXklMxLCrxWewLmYW2d0HSRj0rsj8CPy4&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1247127971&oauth_consumer_key=gDQ2c0OqwtKt51tyV2ANzA&oauth_version=1.0&oauth_signature=Qw65z5ueVxp8QnRyoU4bmxZnVTg%3D

@provider end
Signature is aYqi3i5XI3zEZALugNxo3F6W9Fw=

luoping0425@gmail.com
Sunny August 12th, 2009 destroy

Exescue me, I am also new to this, because our web had already finished the login part, but not used plugins above, we wrote the must_login function instead of login_required, but i don’t know how to change oauth_required, can you tell me what should i do, or i just should install the plugin?

andreapigato@gmail.com
Andrea Pigato August 21st, 2009 destroy

Hi, I’m trying to figure out if I can, as a consumer, let users authenticate with oauth without the need of local credentials:

signup:
my website -> oauth -> twitter -> get user profile

login:
my website -> oauth -> login on twitter = login on my website

Thanks in advance

rowoot@gmail.com
Michael September 9th, 2009 destroy

Hello,

Great plugin. I jus wanted to know, is it possible to use this with AuthLogic Authentication in Rails ?

Although I have tried using it, I wanted to get rid of the approve app screen and wanted auto approve. Can I make it auto approve ?

Secondly, I tried integrating Authlogic with this plugin, but culdn`t :(

Regards

pelle@stakeventures.com
Pelle Braendgaard September 9th, 2009 destroy

@Michael

I want it to be less painful to integrate with authlogic or clearance. As it turns out it’s not too bad.

You need to make sure the following 3 protected methods are implemented in application controller.:

logged_in?, current_user and authorize?

You may already have these, but as authlogic doesn’t have a generator you might not.

  • logged_in? should return true if user is logged in.
  • current_user should return the current user
  • authorize? you can just have return true

If you’re still having problems try sending a message with the errors you are getting to the mailing list and I’m sure we’ll get you sorted out in no time.

rowoot@gmail.com
Michael September 10th, 2009 destroy

@Pelle

Thanks for replying so soon. I would just like to let you know that I have managed to get it up and running with Authlogic :)

I have made my rails site as OAuth Provider and is working fine.

I have a PHP app which will be the consumer. I have managed to get it up and running as well i.e the API requests are working :)

Although, when I logout of my Rails site, I assume, the PHP app should automatically realize this and provide me with a request token once again, instead it still shows me as logged in and gives my access to the Rails site API. Is this a bug ? (I am using the OAuth library for PHP and it is working fine with Twitter, so I am assuming either there is something I am overlooking in my Rails app as OAuth Provider, since the PHP app is flawless)

Thanks Once again :)

rjharmon0316@yahoo.com
Randy September 16th, 2009 destroy

Click to Continue Reading… link doesn’t work :( so I can read the whole post. Any help?

rjharmon0316@yahoo.com
Randy September 17th, 2009 destroy

Click to Continue Reading works fine now, thanks. I’m seeing @pelle’s email address in the form now, though. Weird.

Randy September 22nd, 2009 destroy

The Continue Reading link is broken again :(

pelle@stakeventures.com
Pelle Braendgaard September 22nd, 2009 destroy

I don’t even see a Continue Reading link and there shouldn’t be one. What browser are you using?

bmsatierf@gmail.com
bmsatierf September 24th, 2009 destroy

@Pelle

Is there a way to use the oauth-plugin in a Rails 2.2.2 application with the Engines plugin? I’m getting the following error when trying
to add a new OAuth Client (oauth_clients_controller.rb:16 @client_application.save):

NameError: uninitialized constant OAuth::Server

Note that this error just occurs in an Rails 2.2.2 application with the Engines plugin (tag 2.2.2).

Here is the setup do reproduce the error above:

Create a Rails 2.2.2 application from scratch:

rails _2.2.2_ provider cd provider

Install the engines plugin with the tag 2.2.2:

script/plugin install --revision 'tag 2.2.2' git://github.com/lazyatom/engines.git

Add the following line to the top of config/environment.rb. You should add this line just below the require for Rails’ own boot.rb file.

require File.join(File.dirname(__FILE__), '../vendor/plugins/engines/boot')

Install the restful-authentication plugin:

script/plugin install git://github.com/technoweenie/restful-authentication.git

Rename the restful-authentication folder to avoid a NameError exception (lighthouse tracker ticket):

mv vendor/plugins/restful-authentication vendor/plugins/restful_authentication

Run the restful-authentication generator:

script/generate authenticated user sessions

Add the following in the gem dependency section of config/environment.rb:

config.gem "oauth", :version => '0.3.6' config.gem "oauth-plugin", :version => '0.3.10'

Run the rake gem install command:

rake gems:install

Run the oauth generator:

script/generate oauth_provider

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]

Run your migrations and open a console:

rake db:migrate script/console

Now print the OAuth::Server:

p OAuth::Server

And you will see the following error:

NameError: uninitialized constant OAuth::Server from /Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/dependencies.rb:442:in `load_missing_constant' from /Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/dependencies.rb:77:in `const_missing' from (irb):1

Any tip?

B.

herestomwiththeweather@gmail.com
Tom September 27th, 2009 destroy

i’m also seeing a continue link using firefox 3.5.3 on ubuntu. the post seems to be cut off there with the last text being: “Easy before filter to provide oauth protection on your actions”

i’ll try another browser/OS and see what happens…

herestomwiththeweather@gmail.com
Tom September 27th, 2009 destroy

this post works fine with firefox 3.5.3 on windows. (not sure why it’s bugging out on ubuntu with 3.5.3)

Paul October 15th, 2009 destroy

The article is cut off right after the enumeration of Provider Features. The Continue Reading… link just points to this same page.

al.pendergrass@gmail.com
Al November 21st, 2009 destroy

The article is cut off for me as well (tried several browsers, Mac and Win) and I suspect there is something in it that I need to know. I am having problems getting login_or_oauth_required filter to work. My app is throwing UnknownSignatureMethod exception and I cannot figure out what I’m missing.

Could you provide the full article? Thanks.

dmitry@custommode.com
dmitry December 29th, 2009 destroy

Anybody knows if it’s possible to make oauth work with devise as an authentication solution. I have to use http://github.com/plataformatec/devise/ since at this time this is the only authentication solution that works with mongo mapper. Any help would be greatly appreciated.

aditya.sanghi@risingsuntech.net
Aditya Sanghi January 18th, 2010 destroy

Hi Pelle,

The document gets cut off and there is a continue reading link below. Using FF 3.5.7 on Windows. Please help!

Cheers,
Aditya

suprie1983@yahoo.com
suprie March 24th, 2010 destroy

hi, i just tried to use this plugin… and it works like a charm.

Just wondered, when i’m adding new clients, what does “Callback URL” mean ?

Thanks

sshaikh@hotmail.com
Shak June 21st, 2010 destroy

>You need to make sure the following 3 protected methods are implemented in application controller.:

>logged_in?, current_user and authorize?

Should that be “authorized?”? If not, I get a authorized? method not found error, called by login_or_oauth_required.

If you did want that to return true, then OAuth doesn’t work (it allows all users).

dennismonsewicz@gmail.com
Dennis September 14th, 2010 destroy

I just installed the 2 oauth gems and when I ran the rails generate oauth_provider I received this error: Could not find generator oauth_provider. I am using Rails 3 with Ruby 1.9. Can this be done using Rails 3?

dennismonsewicz@gmail.com
Dennis September 14th, 2010 destroy

Nevermind! I figured it out using the reply in your google forum. Thanks!

http://groups.google.com/group/oauth-ruby/browse_thread/thread/12f9f09a7b3190bb

saurabh.purnaye@synechron.com
Saurabh Purnaye January 17th, 2011 destroy

Hi Pelle,
Thanks a ton for blog about oauth-plugin
I am using oauth and oauth-plugin with rails 3, authentication system used is devise.
here is my gemfile.

gem ‘devise’, :git => “http://github.com/plataformatec/devise.git”
gem ‘oauth’, :git => “http://github.com/pelle/oauth.git”
gem ‘oauth-plugin’, :git => “http://github.com/alsemyonov/oauth-plugin.git”, :branch => “rails3”

I have added following code in my application controller.

require ‘oauth/request_proxy/rack_request’
require ‘oauth/controllers/application_controller_methods’
class ApplicationController < ActionController::Base
include OAuth::Controllers::ApplicationControllerMethods
alias :logged_in? :user_signed_in?
alias :login_required :authenticate_user!

I am able to access GET and DELETE methods thr API but the POST and PUT is giving 401 error.
Could you please suggest any changes?

Thanks
Saurabh

sandro.padin@gmail.com
Sandro Padin January 21st, 2011 destroy

Hi Pelle,

Maybe I’m a little too new to Rails, and I’m not sure what’s going on, but are the generators supposed to generate views when using:

rails g oauth_provider ?

I’m using rails 3, I also pointed bundler to load the gem from your rails3 branch on github.

I see the views in your source, but they appear to get generated for me.

I have this on my application.rb as well

config.generators do |g|
g.orm :active_record
g.template_engine :erb
end

karismafilms@gmail.com
Alex Savin March 1st, 2011 destroy

>>Maybe I’m a little too new to Rails, and I’m not sure what’s going on, but are the generators supposed to generate views?

I have the same question. Tried this with Rails 3, no views are generated. Got generated following models + migration file:

identical app/models/client_application.rb identical app/models/oauth_token.rb identical app/models/request_token.rb identical app/models/access_token.rb identical app/models/oauth2_token.rb identical app/models/oauth2_verifier.rb identical app/models/oauth_nonce.rb

No views. How do I get them?

philipjingram@yahoo.com
pjammer April 30th, 2011 destroy

for those that need it:

rails g oauth_provider oauth

that will create the views and stuff. You need a NAME after the command. I chose oauth, i guess it could be anything that made sense.

dlogan21@gmail.com
MrPlazmaDude July 26th, 2011 destroy

You have saved me many days of work and are now my hero!

lyosha@gmail.com
Alex September 16th, 2011 destroy

Hi Pelle -

Does the oauth-plugin work with Devise as its authentication system? I have to use Devise to work with MongoDB.

I’m also getting this error when trying to load the OAuth Rack filter: no such file to load — oauth/rack/oauth_filter (LoadError)

I have the gems and plugin installed and oauth_provider generated.

Thanks!

Alex

christoffer@stoffiplayer.com
christoffer September 24th, 2011 destroy

Hi,

I followed your instructions and everything seem to be working out so far. However, I am now creating a second app in which I want to authorize with OAuth.

But I have no clue how this should be done. If I go to the /oauth/authorize url I get the login but how do I access the consumer name? What extra parameters should be sent with the GET request?

Thanks