Using OAuth Gem for Yahoo! OAuth
For Yahoo! OAuth, you need to handle OAuth Session Extension.
It is much harder than normal OAuth 1.0, normal one is enough hard though :(
I've talked with pelle, OAuth Gem developer and the guy who named Yahoo!'s OAuth "YAuth", about handling Yahoo! specific extension in OAuth Gem, and reached a conclusion not to do so.
Instead to support YAuth, I overwrote some OAuth gem classes.
First, you need to add "session_handle", "expires_in" and "authorization_expires_in" in the OAuth AccessToken class.
(Yes, you also need migration to add those columns to DB.)
-
# yahoo specific access token
-
class OAuth::AccessToken::Yahoo <OAuth::AccessToken
-
# :external_user_id seems to be Y! original attribute
-
attr_accessor :external_user_id, :session_handle, :expires_in, :authorization_expires_in
-
def initialize(consumer, token, secret, options = {})
-
super(consumer, token, secret)
-
@external_user_id = options[:external_user_id]
-
@session_handle = options[:session_handle]
-
@expires_in = options[:expires_in]
-
@authorization_expires_in = options[:authorization_expires_in]
-
end
-
end
Below is basically same changes for RequestToken class.
-
# yahoo specific request token
-
class OAuth::RequestToken::Yahoo <OAuth::RequestToken
-
def get_access_token(options={})
-
response = consumer.token_request(consumer.http_method, consumer.access_token_path, self, options)
-
access_token = OAuth::AccessToken::Yahoo.new(
-
consumer,
-
response[:oauth_token],
-
response[:oauth_token_secret],
-
{
-
:external_user_id => response[:xoauth_yahoo_guid],
-
:session_handle => response[:oauth_session_handle],
-
:expires_in => response[:oauth_expires_in],
-
:authorization_expires_in => response[:oauth_authorization_expires_in]
-
}
-
)
-
end
-
end
And this is the actual Rails model using those.
-
# Yahoo! OAuthToken
-
class YAuthToken <ActiveRecord::Base
-
-
class Exception <StandardError; end
-
-
def to_access_token
-
refresh! if expired?
-
OAuth::AccessToken::Yahoo.new(self.class.consumer_digested, self.token, self.secret)
-
end
-
-
def self.establish_access_token!(user, token, secret = "", oauth_verifier = "")
-
request_token = OAuth::RequestToken::Yahoo.new(self.consumer, token, secret)
-
access_token = request_token.get_access_token(:oauth_verifier => oauth_verifier)
-
access_token = self.new(
-
:user_id => user.id,
-
:token => access_token.token,
-
:secret => access_token.secret,
-
:external_user_id => access_token.external_user_id,
-
:session_handle => access_token.session_handle,
-
:expires_in => access_token.expires_in,
-
:authorization_expires_in => access_token.authorization_expires_in
-
)
-
access_token.save!
-
rescue Net::HTTPServerException => e
-
raise YAuthToken::Exception.new(e.message)
-
end
-
-
def self.consumer
-
@consumer ||= OAuth::Consumer.new(
-
self.config[:oauth_consumer_key], self.config[:oauth_consumer_secret],
-
{
-
:site => 'https://api.login.yahoo.com',
-
:scheme => :body,
-
:request_token_path => '/oauth/v2/get_request_token',
-
:authorize_path => '/oauth/v2/request_auth',
-
:access_token_path => '/oauth/v2/get_token'
-
}
-
)
-
end
-
-
def self.consumer_digested
-
@consumer_digested ||= OAuth::Consumer.new(
-
self.config[:oauth_consumer_key], self.config[:oauth_consumer_secret],
-
{
-
:site => 'http://social.yahooapis.com',
-
:realm => 'yahooapis.com'
-
}
-
)
-
end
-
-
def self.config
-
@config ||= YAML.load_file("#{SMART_CORE_ROOT}/config/yahoo.yml")[RAILS_ENV].symbolize_keys
-
rescue StandardError => e
-
raise StandardError.new("config/yahoo.yml could not be loaded.")
-
end
-
-
private
-
-
# Yahoo! requres access_token refresh every hour
-
def expired?
-
if self.created_at <= Time.now - self.authorization_expires_in
-
raise YAuthToken::Exception.new('Yahoo! OAuth token are expired.')
-
else
-
self.updated_at <= Time.now - self.expires_in
-
end
-
end
-
-
def refresh!
-
request_token = OAuth::RequestToken::Yahoo.new(self.class.consumer, self.token, self.secret)
-
access_token = request_token.get_access_token(:oauth_session_handle => self.session_handle)
-
self.token = access_token.token
-
self.secret = access_token.secret
-
self.session_handle = access_token.session_handle
-
self.expires_in = access_token.expires_in
-
self.save!
-
rescue Net::HTTPServerException => e
-
raise YAuthToken::Exception.new(e.message)
-
end
-
-
end
This model checks expiry of access token and authorization, and refresh the token when token is expired, but authorization is still available.
When you got an 401 response when refreshing the access token, think the authorization is manually revoked by user and not refreshable anymore.



