The insider's guide to everything sparqcode
Header image

Accessing Yahoo Contacts Using the Ruby OAuth Gem

Posted by Mike on March 30, 2011 in Technical Development

Recently I implemented a feature for our up and coming referral program that lets you refer people using your Yahoo and Google contacts. As part of this I needed to work with Yahoo’s own implementation of the OAuth standard. This interaction caused me quite a bit of pain, so I decided to write up a little tutorial to help out other struggling with this problem.

In order to access a Yahoo contact your first order of business will be to get an application key and an application secret from https://developer.apps.yahoo.com/projects.

Yahoo verifies the callback url you provide to be from the same domain as what you registered for (you can’t register with localhost). Because of this you will need to override your hosts file to match your domain, in my case I had an entry like

127.0.0.1 www.sparqcode.com

With all that in place, you will need two oauth consumers: one to authenticate and one to actually consume the data from Yahoo.

  def yahoo_oauth_consumer
    OAuth::Consumer.new(YahooOauthCredentials::KEY,
        YahooOauthCredentials::SECRET, {
          :site                 => 'https://api.login.yahoo.com',
          :scheme               => :query_string,
          :request_token_path   => '/oauth/v2/get_request_token',
          :access_token_path    => '/oauth/v2/get_token',
          :authorize_path       => '/oauth/v2/request_auth'
        })
  end

  def yahoo_calendar_consumer
    OAuth::Consumer.new(YahooOauthCredentials::KEY,
        YahooOauthCredentials::SECRET,
        {
          :site => 'http://social.yahooapis.com'
        })
  end

In your initial view, you need to redirect to Yahoo’s authorization URL.

    request_token = yahoo_oauth_consumer.get_request_token(:oauth_callback => yahoo_callback_contact_import_url)
    redirect_to request_token.authorize_url

Once your user has granted your application access to her contact list, you need to actually parse the response.

  def yahoo_callback
    if(params[:oauth_token] && params[:oauth_verifier])
      request_token = OAuth::RequestToken.new(yahoo_oauth_consumer, session['request_token'], session['request_secret'])

      access_token = request_token.get_access_token(:oauth_verifier => params[:oauth_verifier])

      access_token.consumer = yahoo_calendar_consumer
      yahoo_guid = access_token.params[:xoauth_yahoo_guid]

      response = access_token.get("/v1/user/#{yahoo_guid}/contacts?format=json&count=max")
      json = ActiveSupport::JSON.decode(response.body)

      @name_email_map = parse_yahoo_contacts_response(json)
    end
  end

  def parse_yahoo_contacts_response(json)
    name_email_map = {}

    return name_email_map if json['contacts']['contact'].nil?

    json['contacts']['contact'].each do |contact| 

      name = nil
      email = nil

      contact['fields'].each do |field|
        field['type']

        if field['type'] == 'name'
          name = "#{field['value']['givenName']} #{field['value']['familyName']}"
        end 

        if field['type'] == 'email'
          email = field['value']
        end
      end

      if(email)
        name ||= email
        name_email_map[name] = email
      end
    end

    name_email_map
  end

Any questions please leave a comment and I’ll do my best to answer.

Full code for handling storing session variables and redirecting


  def yahoo_import
    request_token = yahoo_oauth_consumer.get_request_token(:oauth_callback => yahoo_callback_contact_import_url)
    session['request_token'] = request_token.token
    session['request_secret'] = request_token.secret
    redirect_to request_token.authorize_url
  end

  def yahoo_callback
    if(params[:oauth_token] && params[:oauth_verifier])
      request_token = OAuth::RequestToken.new(yahoo_oauth_consumer, session['request_token'], session['request_secret'])

      access_token = request_token.get_access_token(:oauth_verifier => params[:oauth_verifier])

      yahoo_guid = access_token.params[:xoauth_yahoo_guid]

      access_token.consumer = yahoo_calendar_consumer
      yahoo_guid = access_token.params[:xoauth_yahoo_guid]

      response = access_token.get("/v1/user/#{yahoo_guid}/contacts?format=json&count=max")
      json = ActiveSupport::JSON.decode(response.body)

      @name_email_map = parse_yahoo_contacts_response(json)

    end
  end

You can follow any responses to this entry through the RSS 2.0 You can leave a response, or trackback.

2 Responses

  • AbidMahmood says:

    Hi!

    Thanks for the great post. I have spent like 6-7 hours fixing oauth issues with yahoo and I must say yahoo has a really bad implementation of oauth. I googled my way to your post but unfortunately i couldn’t get it to work.

    I have couple of questions will be great if you could answer.

    you use session['request_token'], session['request_secret'] .. but you never put those things in the session..

    also currently i am getting the error invalid signature.. can you help me out with this.

    thanks

  • Mike says:

    This is how we handle storing of session variables. Hope this helps.

    def yahoo_import
    request_token = yahoo_oauth_consumer.get_request_token(:oauth_callback => yahoo_callback_contact_import_url)
    session['request_token'] = request_token.token
    session['request_secret'] = request_token.secret
    redirect_to request_token.authorize_url
    end

    def yahoo_callback
    if(params[:oauth_token] && params[:oauth_verifier])
    request_token = OAuth::RequestToken.new(yahoo_oauth_consumer, session['request_token'], session['request_secret'])

    access_token = request_token.get_access_token(:oauth_verifier => params[:oauth_verifier])

    yahoo_guid = access_token.params[:xoauth_yahoo_guid]

    access_token.consumer = yahoo_calendar_consumer
    yahoo_guid = access_token.params[:xoauth_yahoo_guid]

    response = access_token.get(“/v1/user/#{yahoo_guid}/contacts?format=json&count=max”)
    json = ActiveSupport::JSON.decode(response.body)

    @name_email_map = parse_yahoo_contacts_response(json)
    end
    end



Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>