Developing OAuth clients in Ruby
On the request of many people here is a quick guide to developing OAuth Consumer Application (Consumer==Client in OAuth Speak) in Ruby.
I will be using Agree2 as the sample application here, so feel free to go Register and load up a irb session to follow along. You could also do the same with Twitter’s OAuth or any other OAuth server.
The general process is:
- Register your consumer application with the OAuth compliant service to receive your Consumer Credentials (This is only done once)
- You initiate the OAuth Token exchange process for a user by requesting a RequestToken from the Service
- You store the RequestToken in your database or in the users session object
- You redirect your user to the service providers authorize_url with the RequestToken’s key appended
- Your user is asked by the service provider to authorize your RequestToken
- Your user clicks yes and is redirected to your CallBack URL
- Your callback action exchanges the RequestToken for an AccessToken
- Now you can access your users data by performing http requests signed by your consumer credentials and the AccessToken.
- ????
- PROFIT!!!
Get your Consumer Credentials
Once you are logged in to Agree2 click the Manage OAuth Applications link in the footer:

All OAuth capable applications require you to register your own application first to get your consumer credentials:

Click Register your application

Enter the name of your application, the url of your application, the callback url and an optional support url.
The callback url is the url that Agree2 redirects to after a user has authorized a token for you. For now just enter a url like http://myapp.com/oauth_client/callback. Click register and hey presto:

These are your applications Consumer Credentials.
Hooking up your code
As we are nice guys here at Agree2 also provides actual sample Ruby code on the credentials screen. I will go through this step by step.
First of all you need to install the oauth gem (make sure you have at least 0.2.2):
sudo gem install oauthYour code needs to require the gem and the consumer part of the library:
gem 'oauth'
require 'oauth/consumer'Instantiate your Consumer object with your credentials:
@consumer=OAuth::Consumer.new "AVff2raXvhMUxFnif06g",
"u0zg77R1bQqbzutAusJYmTxqeUpWVt7U2TjWlzbVZkA",
{:site=>"https://agree2.com"}Now request a token from Agree2. This method actually performs a signed http request to https://agree2.com/oauth/request_token :
@request_token=@consumer.get_request_tokenNow you need to redirect the user to the authorize_url
If you’re in irb just output the url:
@request_token.authorize_urlIn a real rails application you would perform a redirect:
redirect_to @request_token.authorize_urlThe user will be taken to this screen to authorize the token:

I think we need to work a bit on the user interface for this. But it does work. The user authorizes the token. and the user is redirected to the callback url you specified earlier.
In your callback action you now need to exchange the request token for an AccessToken:
@access_token=@request_token.get_access_tokenNow you are ready to do whatever you wanted to do:
# Request all your users agreements
@response=@access_token.get "/agreements.xml"The access token object has all the normal http request methods and returns a standard ruby http response.
Our next step is to integrate this with ActiveResource. This is being worked on now. Once this is done I will update this tutorial.
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.
Follow me on Twitter
This is all very informative! There is almost a step-by-step illustration to the whole process. Thanks. I shall follow the general procedure.
Your tutorial is missing some key steps.
It assumes the @request_token and @consumer stay around. This obviously isn’t true if you want some way to only requiring authorization once, but then repeatedly access resources – say, in a Rails app.
What are the steps to recreating a client after you have stored the Access Tokens?
thanks for your tutorial~!
what a fantastic simple steps.
cheer up~!
<p>@Andrew, get authorised tokens once (using Ruby or some <a href=“http://term.ie/oauth/example/client.php”>online test client</a>) and ensure the server keeps the tokens authorised for a long time. Next:</p>
<pre>
@consumer= (just like above)
accesstoken = OAuth::AccessToken.new(consumer, ‘access token’, ‘access token secret’)</pre>
To set another User-Agent or Accept in the HTTP headers, use something like:
response=access_token.get “/agreements.xml”, {"User-Agent" => “my user agent”}Since it’s not completely obvious:
Once you have the access token you can get the token string and the token secret (respectively) as follows:
@access_token.token @access_token.secretYou would need to save these two strings and use them to reconstruct the access token later:
access_token = OAuth::AccessToken.new(consumer, ‘token’, ‘secret’)Hope this helps.
Hi,
Re-constructing a new access token as
access_token = OAuth:AccessToken.new(consumer, ‘token’, ‘secret’) does not work for Yahoo OAuth. I keeps getting signature_invalid error. Are there something wrong with the encoding of the oauth_signature parameter?Thanks,
Teefan
I am trying to make a client (in python, but it’s not the problem).
I can’t really understand how the user will interact (or will be provided option) if it’s CLI (or even if its GUI – how to design to ""let the server show the option"" – any API call?)?
i’m trying to test all of this within irb, I can generate the request token and i go and approve the request in the browser, but when i try to access the tokeni get this:
@
access_token=request_token.get_access_tokenpath: /oauth/access_token
OAuth::Unauthorized: 401 Unauthorized
from /Library/Ruby/Gems/1.8/gems/oauth-0.3.6/lib/oauth/consumer.rb:201:in `token_request’
from /Library/Ruby/Gems/1.8/gems/oauth-0.3.6/lib/oauth/tokens/request_token.rb:18:in `get_access_token’
from (irb):23
@
on the server the request goes through, but then returns the 401
@
Processing OauthController#access_token (for 64.183.112.84 at 2009-10-22 15:58:36) [POST]
Parameters: {"oauth_nonce"=>"uHk3HvbmD1N7XnWGoAZF3M58OalRIQJTmcuW2AVdQ", “action”=>"access_token", “oauth_timestamp”=>"1256252307", “oauth_signature_method”=>"HMAC-SHA1", “controller”=>"oauth", “oauth_token”=>"GpfsPinMUSoBYgzx38ZJ", “oauth_consumer_key”=>"CrOSkI3UJjYXQzvxwukC", “oauth_signature”=>"0iSPV6D+Yjq1U03yeNWEC7s2frw=", “oauth_version”=>"1.0"}
[[4;35;1mOauthToken Columns (4.0ms)[[0m [[0mSHOW FIELDS FROM `oauth_tokens`[[0m
[[4;36;1mOauthToken Load (0.0ms)[[0m [[0;1mSELECT * FROM `oauth_tokens` WHERE (`oauth_tokens`.`token` = ‘GpfsPinMUSoBYgzx38ZJ’) LIMIT 1[[0m
[[4;35;1mRequestToken Columns (4.0ms)[[0m [[0mSHOW FIELDS FROM `oauth_tokens`[[0m
[[4;36;1mClientApplication Columns (0.0ms)[[0m [[0;1mSHOW FIELDS FROM `client_applications`[[0m
[[4;35;1mClientApplication Load (0.0ms)[[0m [[0mSELECT * FROM `client_applications` WHERE (`client_applications`.`id` = 1) ^[[0m
^[[4;36;1mUser Columns (4.0ms)[[0m [[0;1mSHOW FIELDS FROM `users`[[0m
[[4;35;1mUser Load (0.0ms)[[0m [[0mSELECT * FROM `users` WHERE (`users`.`id` = 2) ^[[0m
^[[4;36;1mOauthNonce Columns (0.0ms)[[0m [[0;1mSHOW FIELDS FROM `oauth_nonces`[[0m
[[4;35;1mSQL (0.0ms)[[0m [[0mBEGIN[[0m
[[4;36;1mOauthNonce Load (0.0ms)[[0m [[0;1mSELECT `oauth_nonces`.id FROM `oauth_nonces` WHERE (`oauth_nonces`.`nonce` = BINARY ‘uHk3HvbmD1N7XnWGoAZF3M58OalRIQJTmcuW2AVdQ’ AND `oauth_nonces`.timestamp = 1256252307) LIMIT 1[[0m
[[4;35;1mOauthNonce Create (0.0ms)[[0m [[0mINSERT INTO `oauth_nonces` (`created_at`, `timestamp`, `updated_at`, `nonce`) VALUES[[0m
[[4;36;1mSQL (28.0ms)[[0m [[0;1mCOMMIT[[0m
Completed in 112ms (View: 0, DB: 40) | 401 Unauthorized [http://claude.circlestreet.com/oauth/access_token]
@
Any ideas?
@claude
Replace your
@access_token = @request_token.get_access_token
with
@access_token = @request_token.get_access_token(:oauth_verifier => params[:oauth_verifier])
Earlier it worked without :oauth_verifier, but is required now.
While attempting to register my app on OAuth service provider I’m getting the following error:
ActiveRecord::StatementInvalid in Oauth clientsController#create
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘key FROM `client_applications` WHERE (`client_applications`.key = ’NHpO78hhm’ at line 1: SELECT key FROM `client_applications` WHERE (`client_applications`.key = ‘NHpO78hhmZzJWESLAMGw’)
I think this is due to the key attribute in client_applications table. We need to access this attribute as quoted `key` but for some reason ActiveRecord seems to behave strangely.
Hi,
I tried the sample code with MySpace OAuth API, but I keep getting “OAuth::Unauthorized (401 Unauthorized)” errors.
Here is code:
def test_oauthconsumer_key = “http://www.myspace.com/533816209”
consumer_secret = “03edd8f05e33428285582e4ae5be116149f9ff9e680e4227a19975847600259c”
#consumer_key = “ea873b9d77994e4293b05d097149f88d”
#consumer_secret = “a9607a38c1304744bdba00432cb3112912b71a74c6cd4244a89b66e2f87664f0”
@consumer = OAuth::Consumer.new(consumer_key, consumer_secret,
:http_method => :get,
:site=>"http://api.myspace.com",
:request_token_path => OAUTH_REQUEST_TOKEN_URL,
:access_token_path => OAUTH_ACCESS_TOKEN_URL,
:authorize_path => OAUTH_AUTHORIZATION_URL)
#return render(:text => @consumer.inspect)
@request_token = @consumer.get_request_token
session[:request_token] = @request_token
redirect_to @request_token.authorize_url
end
It errors on the line where it tries to get request token. My error log shows:
OAuth::Unauthorized (401 Unauthorized):
/usr/local/lib/ruby/gems/1.8/gems/oauth-0.4.0/lib/oauth/consumer.rb:215:in `token_request’
/usr/local/lib/ruby/gems/1.8/gems/oauth-0.4.0/lib/oauth/consumer.rb:136:in `get_request_token’
/app/controllers/my_space_controller.rb:37:in `test_oauth’
/usr/local/lib/ruby/gems/1.8/gems/actionpack-2.1.0/lib/action_controller/base.rb:1162:in `send’
/usr/local/lib/ruby/gems/1.8/gems/actionpack-2.1.0/lib/action_controller/base.rb:1162:in `perform_action_
…
Any ideas?
Thanks,
Harry
Thanks for this tutorial! I wrote an article about the pros and cons for using OAuth in our application, and why we chose not to use OAuth for the time being.
http://blog.youffiliate.com/2010/05/pros-and-cons-of-openid-authentication-oauth/