Ruby OAuth Nightmare: Using Contacts API
I've been spending the last few days banging my head against the wall on supporting the ability to add a contact to the Google Contacts API in my Rails 3 application. Despite many false starts, I've finally made some progress by employing the Ruby OAuth gem, and following the tutorial here: http://everburning.com/news/google-analytics-oauth-and-ruby-oh-my/
When I follow this in the console, I get further than I do in my Rails app. I can create an access token, authenticate against Google's service with the specific scope of the Contacts API, and apply the oauth_verifier token to get an access token. But when it comes time to push the data, I get this error:
response = at.post("https://www.google.com/m8/feeds/contacts/default/full", gdata)
=> #<Net::HTTPUnauthorized 401 Unknown authorization header readbody=true>
Where does the "readbody=true" header come from, and how would I get rid of it?
But it's worse in the Rails app. I have one controller action ("googlecontacts") that creates the request token and leads the user to the authentication site with Google:
def googlecontacts
@card = Card.find_by_short_link(params[:id])
@consumer = OAuth::Consumer.new(
'anonymous',
'anonymous',
{
:site => 'https://www.google.com',
:request_token_path => '/accounts/OAuthGetRequestToken',
:access_token_path => '/accounts/OAuthGetAccessToken',
:authorize_path => '/accounts/OAuthAuthorizeToken',
:signature_method => 'HMAC-SHA1',
:oauth_version => '1.0'
})
@request_token = @consumer.get_request_token(
{:oauth_callback => 'http://monkey.dev/cards/google_auth?redir='+@card.short_link},
{:scope => "https://www.google.com/m8/feeds/"}
)
session[:request_token] = @request_token
redirect_to @request_token.authorize_url
end
This appears to work; I get a working request token object, and the user is forwarded to the Google service to authenticate. The callback URL ("google_auth") should take the oauth_verifier token to create an access token. Here's the beginning of the controller:
def google_auth
@access_token = session[:request_token].get_access_token(:oauth_verifier=>params[:oauth_verifier])
And here's where it craps out. The error on that last line is:
You have a nil object when y开发者_开发知识库ou didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.[]
But the values that are in there -- the session[:request_token] and the params[:oauth_verifier] -- are present and accounted for in that action! I can't figure out what is nil here.
So I guess I need to figure out this second problem first, but bonus points for answering the first problem as well. :-)
Thanks for reading.
Aaron.
Try setting/getting the session data with a string not symbol, i.e. session["request_token"]
, not session[:request_token]
. I know I've had that issue before in the past.
Unknown authorization header
typically means that your signature didn't match what you sent. I do not recommend the oauth
gem. It's full of bugs and weird issues and it doesn't properly escape certain parameters.
The Signet gem is the officially supported gem for accessing Google APIs in Ruby.
Here's how you'd implement this with Signet:
require 'signet/oauth_1/client'
require 'addressable/uri'
card = Card.find_by_short_link(params[:id])
callback = Addressable::URI.parse('http://monkey.dev/cards/google_auth')
callback.query_values = {'redir' => card.short_link}
client = Signet::OAuth1::Client.new(
:temporary_credential_uri =>
'https://www.google.com/accounts/OAuthGetRequestToken',
:authorization_uri =>
'https://www.google.com/accounts/OAuthAuthorizeToken',
:token_credential_uri =>
'https://www.google.com/accounts/OAuthGetAccessToken',
:client_credential_key => 'anonymous',
:client_credential_secret => 'anonymous',
:callback => callback
)
session[:temporary_credential] = (
client.fetch_temporary_credential!(:additional_parameters => {
:scope => 'https://www.google.com/m8/feeds/'
})
)
redirect_to(client.authorization_uri)
精彩评论