Developing OAuth clients in Ruby
Published February 23rd, 2008 edit replace rm!
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 oauth
Your 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 :
@[email protected]_request_token
Now you need to redirect the user to the authorize_url
If you’re in irb just output the url:
@request_token.authorize_url
In a real rails application you would perform a redirect:
redirect_to @request_token.authorize_url
The 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_token
Now 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 [email protected].
Ajit February 24th, 2008
This is all very informative! There is almost a step-by-step illustration to the whole process. Thanks. I shall follow the general procedure.
Andrew Turner February 27th, 2008
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?
humbroll March 2nd, 2008
thanks for your tutorial~!
what a fantastic simple steps.
cheer up~!
Arjan van Bentem April 19th, 2008
<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>
Arjan van Bentem June 22nd, 2008
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”}Anthony Eden May 27th, 2009
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.
Teefan June 23rd, 2009
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
StanG September 17th, 2009
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?)?
claude October 22nd, 2009
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?
Nilesh November 10th, 2009
@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.
dg January 6th, 2010
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.
harry May 10th, 2010
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
Andy May 12th, 2010
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/
saranya October 11th, 2010
HI
when i follow in this line
access_token=
request_token.get_access_tokenI came across with the following error
401 Unauthorized errror
Anybody plz provide me the solution
Tushar November 30th, 2010
Thanks Nilesh…
for getting access token, following code should be used:
@access_token = @request_token.get_access_token(:oauth_verifier => params[:oauth_verifier])
Vibhor Mahajan May 9th, 2011
3. Making an API call to receive the OAuth 1.0a tokens for the REST API.
Hao September 3rd, 2011
Thanks for this tutorial!
It really helped me understand the oauth gem.
Alex Chaffee November 6th, 2011
.../oauth-0.4.4/lib/oauth/client/helper.rb:64:in `amend_user_agent_header': uninitialized constant OAuth::VERSION (NameError)
to avoid the above, use
require 'oauth'
instead of
require 'oauth/consumer'
hendrik stein December 1st, 2011
Hey Pelle! Thanks for your tutorial – works great for twitter! But when I try to use it against api.discogs.com I always get a “406 Not Acceptable” when i call “get_request_token”
I think this is because the discogs-api only accepts calls including “Accept-Encoding: gzip” in request-header
http://www.discogs.com/developers/oauth.html
http://www.discogs.com/developers/accessing.html#required-headers
Is there a possibiltiy to change the Header before or during the call?! I tried several thing – but without success…
Juuro March 16th, 2012
When I use this:
@access_token = @request_token.get_access_token(:oauth_verifier => params[:oauth_verifier])
I get this error:
oauth.rb:13:in `‘: undefined local variable or method `params’ for main:Object (NameError)
What can I do?
pooja May 14th, 2012
hi,
I am doing the justin.tv api integration in asp.net, but i am not able to get access_token.
even i have other parameters like consumer key , secret, request_token . but when i try 2 get access_token, it raises error. There is no solution in asp.net in google. Kindly suggest the sol.
Thanx,
Pooja
pooja May 14th, 2012
hi,
I got the following error.
When try to get access_Token.
Request for uri: http://api.justin.tv/oauth/access_token failed. status code: Unauthorized headers: Connection: close status: 401 Unauthorized x-runtime: 0.021571 x-ua-compatible: IE=Edge,chrome=1 x-geo: IN Content-Length: 1 Cache-Control: max-age=0, private, must-revalidate Content-Type: text/html; charset=utf-8 Date: Mon, 14 May 2012 04:49:14 GMT Set-Cookie: language=en; domain=.justin.tv; path=/; expires=Fri, 14-May-2032 04:49:14 GMT Server: nginx Via: Twice 0.2 web6:3345 body: