Search code examples
authenticationweb-applicationsoauthyahooyahoo-api

Why do I get HTTP 401 Unauthorized from my call the to Yahoo contacts API?


This is driving me crackers. I'm implementing a friend invite scheme on a website and need access to the user's Yahoo contacts list. To do this, I'm using OAuth and the yahoo REST api. Here's a complete rundown of the sequence of events:

I have a project set up on developers.yahoo.com which is configured to have read access to Contacts. It's on a made-up domain which I point to 127.0.0.1 in my hosts file (On the off-chance that localhost was causing my woes). For this reason, the domain is not verified though my understanding is that this simply means I have less restrictions, not more.

Firstly, on the server I get a request token:

https://api.login.yahoo.com/oauth/v2/get_request_token
    ?oauth_callback=http%3A%2F%2Fdev.mysite.com%2Fcallback.aspx
    &oauth_consumer_key=MYCONSUMERKEY--
    &oauth_nonce=xmaf8ol87uxwkxij
    &oauth_signature=WyWWIsjN1ANeiRpZxa73XBqZ2tQ%3D
    &oauth_signature_method=HMAC-SHA1
    &oauth_timestamp=1328796736
    &oauth_version=1.0

Which returns with (Formatted for vague attempt at clarity):

oauth_token=hxcsqgj
&oauth_token_secret=18d01302348049830942830942630be6bee5
&oauth_expires_in=3600
&xoauth_request_auth_url
    =https%3A%2F%2Fapi.login.yahoo.com%2Foauth%2Fv2%2Frequest_auth
     %3Foauth_token%3Dhxcsqgj
&oauth_callback_confirmed=true"

I then pop-up the xoauth_request_auth_url page to the user and receive a verifier code to my callback page. I then send that back to my server so that I can exchange it for an access token:

https://api.login.yahoo.com/oauth/v2/get_token
    ?oauth_consumer_key=MYCONSUMERKEY--
    &oauth_nonce=yxhd1nymwd03x189
    &oauth_signature=c%2F6GTcybGJSQi4TOpvueLUO%2Fgrs%3D
    &oauth_signature_method=HMAC-SHA1
    &oauth_timestamp=1328796878
    &oauth_token=hxcqgjs
    &oauth_verifier=b8ngvp        <- verifier given via callback
    &oauth_version=1.0

That seems to work, and I get an access token back:

oauth_token=MYVERYLONGACCESSTOKEN--
&oauth_token_secret=MYOATHTOKENSECRET
&oauth_expires_in=3600
&oauth_session_handle=ADuXM093mTB4bgJPKby2lWeKvzrabvCrmjuAfrmA6mh5lEZUIin6
&oauth_authorization_expires_in=818686769
&xoauth_yahoo_guid=MYYAHOOGUID

I then immediately attempt to get the contacts list with the access token and the GUID:

http://social.yahooapis.com/v1/user/MYYAHOOGUID/contacts

(HTTP Header added and formatted with line breaks for clarity...)

Authorization: OAuth
    realm="yahooapis.com",
    oauth_consumer_key="MYCONSUMERKEY--",
    oauth_nonce="nzffzj5v82mgf4mx",
    oauth_signature="moVJywesuGaPN5YHYKqra4T2ips%3D",
    oauth_signature_method="HMAC-SHA1",
    oauth_timestamp="1328796907",
    oauth_token="MYVERYLONGACCESSTOKEN--",
    oauth_version="1.0"

From this call I get a 401 Unauthorized, but it seems impossible to find out why. To sign these calls, I'm using this oath lib on github. I don't think it's doing anything extraordinary or incompatable. For the signature, I'm including the consumer key/secret and the access token/secret. I've looked at the signature base that's being hashed and it looks to be the same form as the examples visible on yahoo's documentation. I'm guessing that I'm missing something from the parameters that isn't being hashed. Is there a way to find out why the call is unauthorized, or does anyone know of an example showing exactly what form the signature base and authorization header must take?


Solution

  • Solved this myself. Adding the answer just in case it happens to help anyone who makes the same silly mistake I did. When I made the API call, I was using the token secret returned from the original request token call instead of the new one returned from the access token call.

    Oops.