Yahoo OAuth Examples

This tutorial is for programmers who are struggling with code that needs to interface directly with an OAuth flow. This is not a general introduction to OAuth.

The OAuth flow can seem byzantine with multiple steps that must be completed before you can make a signed API call.

I have broken down the OAuth flow into individual, self-contained PHP scripts that can be run from the command line, from requesting a token to making a signed API call.

This tutorial focuses on interfacing with Yahoo Social APIs using OAuth 1.0.  Yahoo publishes SDKs that make your life easier, but if you need to debug OAuth problems, then you need to understand the OAuth requests and responses in detail.

My scripts are deliberately devoid of any web session interactions, database interactions, or even command line option handling, just to keep them as simple as possible.  It’s straight, standalone procedural code, no objects.  If you want to change something, just edit the code and run it.

The goal of the code is to be as transparent as possible, to show you exactly what is sent and what is received.  If you look at the code in getreqtok.php, getacctok.php, and refacctok.php, you can see that they can be combined easily into one function, but they are separated for clarity.

For the rest of this tutorial, I will refer to Step numbers which are documented in the YDN OAuth Quick Start Guide’s, Chapter 4, OAuth Authorization Flow.

Step 1

Sign up for a Yahoo api key.

Input: select the list of apis you want to call.
Output: consumer key and consumer secret.

This is self explanatory and requires no code. At the end of the process, you will have a consumer key and a consumer secret. Please keep the consumer secret secret; it is used to sign all of your requests to Yahoo.

Step 2

Get a request token.

input: consumer key and secret
output: xoauth_request_auth_url

Getting a “request token” is the first step on the road to making a signed API call. If a user has never granted your application permission to do something on his behalf, this is where you start.

Take a look at the getreqtok.php script. The get_request_token function is straight forward. You’ll find most of the supporting functions in either globals.php or oauth_helper.php.

Remember to set the OAUTH_CONSUMER_KEY and OAUTH_CONSUMER_SECRET in globals.php before running the script.

Since this is a command line script, just run it like this:
php getreqtok.php

Change the $debug variable from 0 to 1 in globals.php. Rerun the script, and observe the raw request and header and response.

Change the $usePost variable and see how things differ when using HTTP POST instead of GET.

Note that the $callback parameter must be the string ‘oob’ or a url that points back to the domain that you registered with Yahoo when you obtained the consumer key in step 1. The callback will be invoked at the conclusion of step 3.

The get_request_token call is a good endpoint to test your hmac-sha1 signature code, because this is the simplest call to make. You have no tokens at this point nor token secrets.

Try varying the $useHmacSha1Sig variable. This will exercise the code for generating both types of signatures. In your production code, of course, just pick one signature method for this call and stick to it.

A successful response to this step will contain a [request] token, a [request] token_secret, and in Yahoo’s case, an xoauth_request_auth_url. If you have a web application, you can pop-up a window and open this url. If you have a desktop application, instruct the user to cut-and-paste this auth_url (decoded first) into a browser somewhere, if you can’t spawn a browser yourself.

Step 3

Authenticate the user and get the user authorization for your application.

input: xoauth_request_auth_url (step 2)
output: oauth_verifier

There is no code here. For the purposes of this tutorial, cut-and-paste the xoauth_request_auth_url from the conclusion of step 2 into a browser and authenticate yourself.

This step must be done in a web browser of some type, because user authentication must be done on a yahoo server over an SSL connection. This is much safer than having some local application collect a username and password, and sending it to some authentication server.

At the conclusion of this step, you will receive a short string called an “oauth verifier”. If you used ‘oob’ as the callback in step 2, then a web page with the oauth verifier will be shown to the user. Copy this value down and insert it in the script in step 4. If you are writing a web application, your callback url (from step 2) will be invoked with oauth_verifier as one of the parameters.

Step 4

Get the access token that enables making API calls.

input: consumer key and secret (step 1),
input: request_token and secret (step 2),
input: oauth_verifier (step 3)
output: access_token, access_token_secret, session_handle

You’re almost there. At the conclusion of step 4, you will receive an access token that allows you to call all the API end points that you initially signed up for in step 1.

The script getacctok.php demonstrates how to perform this step. It is very similar to the getreqtok.php script from step 2. Only the inputs are different. Fill in the request token and request token secret from step 2, and the oauth verifier from step 3, and run the script.

In the script’s output, note the [access] oauth_token, [access] oauth_token_secret, oauth_session_handle, and the xoauth_yahoo_guid. The access token and secret will be used to sign API calls. When this token expires in 1 hour, you will need it and the session handle to obtain a new access token.

The xoauth_yahoo_guid is the GUID of the user, an id that uniquely identifies the user who authorized you to act on his or her behalf. This will be used when you make an API call.

Step 5

Refresh an expired access token.

input: consumer key and secret (step 1),
input: old_access_token, old_access_token_secret, session_handle (all from step 4)
output: new_access_token, new_access_token_secret

This is NOT a required step until your access token expires. As soon as you complete step 4, you can go straight to making API calls. Access tokens are good for 1 hour, so you only need to refresh the access token if you receive a token_expired error from any OAuth call, or you’re keeping track of time and want to preemptively refresh before the hour is up.

Look at the script refacctok.php. Again, this script is very similar to both getreqtok.php and getacctok.php with the exception of input variables. Fill in the access token, access token secret, and session handle that you obtained from step 4 and run the script.

Make sure that the access token you enter into this script is not already urlencoded, i.e. it should read ‘A=blah’, not ‘A%3Dblah’

The script should output a new access token and accompanying access token secret.

Making an API call

Calling a Yahoo API using OAuth.

input: api_url and data
input: consumer key and secret (step 1)
input: access_token and secret (step 4)
output: response from api call

This is the step you have been working toward: actually making an API call to get the contacts of a user. You can keep using the same access token and secret (from step 4) over and over again for all API calls, until that token expires (in 1 hour).

This is the step where most people run into trouble, because this will have been the first time they have tested their oauth hmac signature code. If you followed my advice from step 2 above, then you should already have good confidence that your hmac signature code works. It is much simpler to debug your signature code in step 2 than here, when you are actually making an API call.

— Calling Contacts API —

Edit the script callcontact.php and enter the access token, access token secret, and guid, all obtained from step 4. Make sure that the access token you enter into this script is not urlencoded, i.e. it should read ‘A=blah’, not ‘A%3Dblah’

Run the callcontact.php script, and it should fetch the first 5 contacts belonging to the user identified by the GUID retrieved from step 4. This script also shows what the Contacts API end point looks like, and demonstrates how to use both matrix parameters and query parameters in the same url.

Edit the script postcontact.php and run it to add a new contact. Pay particular attention to the POST body format and what is and is not part of the signature base string when formulating the request to the server. An OAuth-signed POST or PUT request is the trickiest type of service call to make.

– Calling YQL –
YQL essentially allows you to “select * from Internet”.

Edit the script yql.php and enter the access token and access token secret that were obtained from step 4. Make sure that the access token you enter into this script is not urlencoded, i.e. it should read ‘A=blah’, not ‘A%3Dblah’

Vary the $querynum value from 1 to 3 and run yql.php after each change. Note how the YQL end point changes when requesting personal data vs public data.

Also note how easy it is to get “stuff” using YQL. Query number 3 from the script gets a listing of sushi restaurants in San Francisco:

select Title,Address,Rating from local.search where query="sushi" and location="san francisco, ca" | sort(field="Rating.TotalRatings",descending="true");

That’s the power of YQL.

The best part is, you can play with YQL for real in the YQL console.

HMAC-SHA1 signature

The OAuth HMAC signture generation step from OAuth 1.0 that trips most people up is the generation of the Signature Base String, which requires some esoteric “normalization” operation. You can read about it from the spec directly.
http://oauth.net/core/1.0/#rfc.section.9.1.1
http://oauth.net/core/1.0/#rfc.section.A.5.1

A Signature Base String is a RFC 3986 encoded concatenation of:

  1. An uppercased HTTP method string: GET, POST, etc.
  2. An ‘&’
  3. A url without any parameters (i.e. scheme://fqdn/path)
  4. An ‘&’
  5. All the query parameters (combined for both the API call and those for oauth) encoded according to RFC 3986 AND alpha-sorted by key. DO NOT include the oauth_signature parameter in this step, because you are generating the oauth_signature.

If you read that last paragraph carefully, you’ll note that the stuff in a signature base string is double rfc 3986 encoded. This means that a Yahoo OAuth access token, which is of the form ‘A=blah’ becomes ‘A%3Dblah’ and finally ‘A%253Dblah’ in the normalized Signature Base String.

A Signature Key is the concatenation of:

  1. rfc 3986 encoded consumer_secret
  2. ‘&’
  3. rfc 3986 encoded token_secret

Then you apply the hmac-sha1 function using the signature_key to hash the signature_base_string and finally base64_encode the whole thing:

$sig = base64_encode(hash_hmac('sha1', $signature_base_string, $signature_key))

Odds and ends to keep in mind

  1. Note that the sorting and encoding of query parameters is done both when constructing the query parameter string, and when constructing the HMAC signature base string.
  2. When normalizing the signature base string, the ‘?’ separating the url from the parameters (if you’re using GET) is replaced with a ‘&’.
  3. If you are using POST instead of GET, make sure that the HTTP method string is POST when normalizing the signature base string.
  4. Make sure that you are using the token secret that corresponds with the correct token.
  5. If you get a signature invalid error, check your Signature Base String normalization code. Be careful of the deliberate double encoding.
  6. When debugging, output what you are actually passing to and receiving from the server. Try capturing the actual data that is leaving your machine. If you are testing in Firefox, for example, the Live HTTP Header plugin is great for this.

106 thoughts on “Yahoo OAuth Examples

  1. Pingback: OAuth Examples « Nothing of Value

  2. Thank you for publishing this very good work. The tutorial instructions here and the referenced php scripts are concise, well-written, and THEY WORK. I never learned php, but it works a lot like Perl. The ability to copy/paste and otherwise cross-wire data between my project and these working php scripts has been really helpful.

    I’m working on updating a Macintosh app which currently has an “old skool” del.icio.us — now Delicious client, written in Objective-C. I’ve got all of my OAuth functions working (got my token, can refresh), so I’ve come to the end of your tutorial. I’m still struggling with the Delicious API, though. Getting “signature invalid”, and am using trial and error to figure out where they want their API parameters. Maybe tomorrow.

    One thing I’m confused about is your “Odds and ends to keep in mind : 2.” You say, “When normalizing the signature base string, the ‘?’ separating the url from the parameters (if you’re using GET) is replaced with a ‘&’.” Well, in section 3.4.1.2 of the draft OAuth Standard,
    http://tools.ietf.org/html/draft-hammer-oauth-10#section-3.4.1.2
    it says that only the scheme, host and possibly the port portions of the URI get into the base string. In their second example, the query “?q=1” does not appear in the normalized result “www.example.net:8080”. So, I don’t see where the “?” would come into play.

    • Hi Jerry. I’m glad you found this useful. I don’t have any experience with the Delicious client, but there is the YDN forums that you can also post your questions to, http://developer.yahoo.net/forum/

      As for the signature base string, section 3.4.1.2, which you referenced, is for the base string URI. Take a look at the sub-section just before that, 3.4.1.1. The entire signature base string construction, which contains the http method & uri & query parameters, is explained in 3.4.1.1.

  3. Thanks again. I understand 3.4.1.1 like you said, and got it all working a few days ago. This thing sure is complicated. Took the better part of 3 days to understand it and write the under-hood stuff, and another 3 days to integrate all the hoop-jumping into my app.

  4. Hi
    I am getting following error on calling callcontact.php
    application/x-www-form-urlencoded not supported with OAuth
    Can you help me out??

    • Yes, please don’t set usePost to true. The default is usePost=false and when you invoke callcontact, make sure that it stays false.

      $retarr = callcontact(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET,
      $guid, $access_token, $access_token_secret,
      false, true);

      You cannot use HTTP POST to get contacts, only HTTP GET. The POST code will be useful in the postcontact.php script.

      • Hi Joec

        Using GET method it is throwing following error for callcontact.php
        Please provide valid credentials. OAuth oauth_problem=”additional_authorization_required”, realm=”yahooapis.com”

      • Ajay, it looks like you’re running into the same issue as Raghu. Please see my reply to his comment below.

      • Thanks joec, it is working. I have one question –
        Suppose user granted access to my site, then he comes after few days, in this case i have to store his old session handler, old access token and old secret and then i have to call refacctok.php. Am i right? or is there any other way?
        Because granting the access should be one time

      • Yes, you need to persist the access token and acccess token secret and session handle somewhere.
        When the access token expires, just refresh it using the same method as demonstrated by refacctok.php.
        The only time you need to ever reauthorized the user is when he or she chooses to revoke your application’s access; when that happens, refreshing an access token will not work and you will need to start from the top of the oauth flow again.

  5. Hi,

    I am held up at “Making an API call” with error mentioned below.
    Any idea where iam going wrong.
    “error”: {
    “lang”: “en-US”,
    “description”: “Please provide valid credentials. OAuth oauth_problem=\”addi
    tional_authorization_required\”, realm=\”yahooapis.com\””
    }

    Thanks in advance…

    • This is usually due to your consumer key having greater than 7 scopes. When you registered for a key, please do not select that you want read/write ability to all APIs. You may want to get a new consumer key that only has read/write ability to Yahoo Contacts API.

  6. I am wondering if there is a utility that matches what the HMAC-SHA1 should be for a given text and key. I am stuck on the actual call to the contacts api saying that my signature is invalid. I want to make sure that I am correctly getting my HMAC-SHA1.

  7. Hi guys, I am just letting everything know it works now.

    When creating the signature the token should NOT be encoded.

    However when constructing the request url the token SHOULD be encoded.

    This cost me a few days, hope this will help out others.

  8. Hi,

    I’m getting this error when making a call.

    Undefined index: port in htdocs/im/joechung-oauth_yahoo-d0a273f/oauth_helper.php on line 151

    Please could anyone help me to fix this.

    • Your php has a non default (more anal) error reporting setting, but the examples should continue to run even with that E_NOTICE output.

      You can turn this error off by inserting the following line after the initial “<?php" line in oauth_helper.php:
      error_reporting(E_ALL & ~E_NOTICE);
      Or you can change line 148 of oauth_helper.php to read
      $port = isset($parts['port']) ? $parts['port'] : "";

  9. Joe, I also have to thank you very much for publishing this example.
    Wow, not a simple process.
    Can I ask you 2 things are still struggling with:

    1) I’m the owner and creator of the application, do I still need to go through the URL link to get a verification code etc. to access my app?

    2) How about giving an hint for fantasysports tweak?

    Thanks again for all your help!

  10. …never mind for #2 I figured out: the game ID was the old one, the correct URL to use for fantasysports is:

    $url = ‘http://fantasysports.yahooapis.com/fantasy/v2/league/242.l.222222/teams’;
    where 222222 is the specific number for your league while 242 is a constant for NFL 2010.

    Still wondering about my question #1 (I’m the owner and creator of the app, do I still need to do step 3 and 4 or there is another way to get authorized?)

    thanks.

  11. it looks like the projected stats are not available in the API at least at the moment.
    I’m wondering why? Someone said because Yahoo doesn’t want to publish these made up statistics probably for legal issues.
    However, I don’t see the difference in making them available on the regular FF screen and not in the API which user still need to login and be authorize in order to use it!?!?!

    I wanted to build an app especially to show the projected points, now I don’t have any use for the Yahoo API. 😦

  12. Excellent article and resource. If all tutorials and technical documents were written this way, we’d probably all have more time, money and happiness. Keep up the great work.

    G

  13. {
    “error”: {
    “lang”: “en-US”,
    “description”: “Please provide valid credentials. OAuth oauth_problem=\”timestamp_refused\”, realm=\”yahooapis.com\””
    }
    }

    I am getting this error. It seems there is problem while setting timezone.

    Please help.

    I would really appreciate you quick help.

    Thanks in advance.

    • Make sure your computer’s clock is synchronized to a good time source and ntpd is running. If your computer’s clock is more than 10 minutes skewed from the OAuth Server’s clock, your timestamp will be rejected.

  14. Pingback: Contact importer in C# for Gmail, Hotmail and Yahoo! | Here be DRAGONS!

  15. Awesome! This was the 3rd or 4th OAuth & YQL tutorial that I’ve tried and the first that actually worked. Very excited to move on with the rest of my app. Thank you!

  16. {“error”:{“lang”:”en-US”,”description”:”Please provide valid credentials. OAuth oauth_problem=\”token_rejected\”, realm=\”yahooapis.com\””}}

    I am getting this error.
    Please help.

  17. I’m using coldfusion, not php, but this is by far the most helpful guide out there.

    I’m so close, but getting this error:
    Please provide valid credentials. OAuth oauth_problem=”parameter_rejected: oauth_signature

    its gotta me by signature, which is generated like this:

    —————-

    signmessage

    —————-

    Which generates this:

    GET%26http%253A%252F%252Fsocial.yahooapis.com%252Fv1%252Fuser%252F3Q4WDMFJ7BHQMTXCKSMLH7WGTQ%252Fcontacts%26oauth_consumer_key%253Ddj0yJmk9SFNyUFZmSTJ0NUl3JmQ9WVdrOWRsVjBjV0pRTldjbWNHbzlOVGsyTWpBeU5qWXkmcz1jb25zdW1lcnNlY3JldCZ4PWFm%2526oauth_signature_method%253DHMAC-SHA1%2526oauth_nonce%253D93E81CD3BCAEC52026B27ADF3A91938C%2526oauth_timestamp%253D1305889403%2526oauth_token%253DA%253DgjPvdHfZvFxZe4lnc.JL76ZK4NC7lK7Mgr12TrusgrMiTsixZ5vWtMR9_2_87LFRot0uXhAreTuXREs24TTbvfQWmUsWRR7oK2DS.5A.UCQBYqjlswWWx6TRAcyRyD2DItxAyCaCV6Qf.StesFku_Y9hM0fgkw2niPdvxvUtZ81jtS73Py.tmorqpKepDWWyY_NKz_I7AOmmk.xSxp0Lvjc8Ld2sSirflcKTVSX2q_3xp2zjDohRyCfsTVHWAlA09cXHAaZsMn03tE3aKm.mt891WtH37ZFaVWfFW6hQj5BMCk9cWuIO_K65MXaiyxmN_WA3vBr8QeCXVQyRtAgBnwYalCfE99oVSrpEWbXQ0kbSXvt_qlCY6eKS5hmetnwn09isuMthNFgCceGiz2nx95wImnibWl3FVhhKFaxLwzuxmI3Hz66ypbcL5jDTw.pi5YmBP6yX3W31kDLTjQw0q1bQeEdKpAdedxdugQsNQIUopeyyw1B.xVEg8IcKPbvTzSo3oG90lI7PXEMvUTyJrgEvnJ3vVhl81326nCDbjLeuVS1zM2duUtT5FzmR_vLJpA5k704.GNCdEiBrW8v9nknZ3sxu9vpN9VDqpMwXexokx2fDCN25bbYLyJuBq3NjPLPywBN7mqKZgT9aOr1nozPNr2.C4scNWRVlsgHOZGVucKlYxuI40r7Z6cS37Ji_iOvxTa5R7cG8uupEX8ElqleQ%2526oauth_version%253D1.0%2526xoauth_lang_pref%253Den-us

    Any help is appreciated!

  18. How can I get the user to login with their Yahoo credentials, but not register everytime they visit my app?

    If I save the oauth_token_secret, oauth_token, oauth_session_handle the user never has to enter their credentials anymore.

  19. Your post really helped, although I had a hard time find exact encodings in JAVA but I managed to pull it off. I could not do it using HMAC-SHA1, I was wondering if Yahoo was the culprit. After playing with your code and getting the results I figured out the culprit was my way of encoding. Anyways, thanks a lot.

  20. This was a really helpful tutorial, thanks for the writeup and sample code.

    One problem I ran into right away was that I kept getting the error “consumer_key_rejected” when I was just trying to get my request token. I created my Yahoo! app as “Client/Desktop”, and used ‘oob’ as the callback string, but I still wasn’t having any luck.

    Some searching on the Yahoo! forum lead me to the issue of “scopes” (permissions). I had not added any non-default scopes to my application, since I only planned on using the public APIs. Based on the advice in the forum thread, I added the “Contacts” scope to my Y! app, copied over the newly generated key/secret values, and voila, the getreqtok.php worked.

    Thanks again!

  21. Very Very nice Tutorial!!!

    But my question is – On my site [ My App Page is registered with Yahoo against my Email ID, and GUID is generated against this ID, as a result I can check the AddressBook of myself only ] how I can make other users log in and bring his/her contacts on the surface so he/she can select some of them and send invitations?

  22. Thank you so much for this! I’ve learned a lot more from this post than those linked from the official Yahoo! APIs, which by the way had broken examples and what-nots, which really didn’t help me at all in understanding Yahoo! OAuth system, but yours did and for that, thank you so much.

  23. Hello I having these error when i start run the callconnect.php

    A PHP Error was encountered

    Severity: Notice

    Message: Undefined variable: argv

    Filename: a/globals.php

    Line Number: 10

    A PHP Error was encountered

    Severity: Notice

    Message: Undefined index: port

    Filename: a/oauth_helper.php

    Line Number: 151

    { “error”: { “lang”: “en-US”, “description”: “Please provide valid credentials. OAuth oauth_problem=\”timestamp_refused\”, realm=\”yahooapis.com\”” } }

    What to do and also i am using localhost…

    Thanks in advance

    • The timestamp provided is invalid (either it doesn’t have the right format, or it’s out of the acceptable window.
      Make sure your system clock is synchronized to some good time source.

  24. Hi, I am trying to understand how I can send/receive IM from yahoo ID. I wanna use PHP on a free hosting server.

  25. do u have any idea why i cannot run this into YQL
    $url = ‘http://query.yahooapis.com/v1/yql’;
    $params[‘q’] = ‘INSERT INTO social.updates (guid,title,description ,link,iconURL) VALUES (me,”ssss”,”as” ,”http://www.uuu.com”,”http://www.exposin.com/external/favicon.gif”)’;
    I revive this :
    cbfunc({ “query”: { “count”: 1, “created”: “2011-10-17T00:40:07Z”, “lang”: “en-US”, “results”: { “status”: “error” } } });

    • I also have problems like it. And I don’t understand what reason. If you can solve this problem. Please let me know

  26. Hi,

    I’m trying to update my rosters list using PUT method as described in yahoo’s doc. I’m sending the headers for authentication and the response i’m getting is

    “OAuth oauth_problem=”signature_invalid”, realm=”yahooapis.com” ”

    Can you please help to sort out this issue?

    Here is the code

    $content = fopen($file_name, ‘r’);

    $curl_opts = array(CURLOPT_URL => $url,
    CURLOPT_PORT => $port,
    CURLOPT_PUT => true,
    CURLOPT_SSL_VERIFYHOST => false,
    CURLOPT_SSL_VERIFYPEER => false,
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_INFILE => $content,
    CURLOPT_INFILESIZE => filesize($file_name),
    CURLOPT_BINARYTRANSFER => true,
    CURLOPT_RETURNTRANSFER => true);

    Here are the request headers.

    “PUT /fantasy/v2/team/257.l.589028.t.1/roster/ HTTP/1.1 Host: fantasysports.yahooapis.com Accept: */* Authorization: OAuth realm=”yahooapis.com”,oauth_consumer_key=”dj0yJmk9UnhBOTZLdTNHNE1pJmQ9WVdrOVNFOTNUR1IyTkhNbWNHbzlNVFUxTXpBd056azJNZy0tJnM9Y29uc3VtZXJzZWNyZXQmeD0wNQ–“,oauth_nonce=”1016567600″,oauth_signature_method=”HMAC-SHA1″,oauth_timestamp=”1320843305″,oauth_token=”A%3Ddnh_c5PQo1zYONnvVkC5_iY16Lr7s2NIT8Gx17JkhVodwQjag4vy.XrOAPK9OP8Wku7awb7Ic96rNQFQXdZZHcH07HuBowWOfEsp4bMp0n1Er8dpvKn4aR3RpZC3ZX9iBQfTW4Dz0MJy3ub230SvFrGMT.GBeSk0huxG.WQih.2VfnU1soNidBMt9lT.Srf06AF56kX8u01sdgoyCYuQgOrWA5wOpjNDW6Dv3vtS5LhUwONSp9R8cnAJT1GJOnuwrOu4Sx5BvUWszuhBF5PMCkSCup6QVKlw52sCDnhKK4ZDSEM0C8mGRcKF96yp34U7O75nHLc56qOoQVkAaSzPx4ONDKo1kVDNBN1ol5U.LZMEeoG8YkYPxOmVcQ_GAMQGQYTMLHoHNxn_9UynVdTOAU4W1IpmMLDvCjB3PfZh7_QfdUl07FYPCpYWXcJzOXtWiUjx03tGRNQfxwbBFjM0bSptEDo6f5qJU2WoDhQiTj4bBlZc3PhuycbbxtFuLJ7R.ZGIL924ytv7tEdAsoxUqYdYHsQ5_4vwSLv8XbDeuj0tV.DxVjvEAPbBCojGPZLcE9IFQPgpCZ6RWdtQERpcAyT4IUHzed9oc5MDz53Usw1PdCCibjvZi.1wJv.gCWLM6ypy1.Aga9NXMrlCyPZgdpM8WdVC3cjrQ7SPLNgFbEzRqh2L7ROruE8bf_piNw6ZEz8qUBZL0f5CtfNjxzDZUfaVJM7vdr52jIDLMrl2zya4ulm5nitp9aF9.KESLZgqCsjhJaCqv5GvSNG6″,oauth_version=”1.0″,oauth_signature=”fVN8xf95DVQ4BsfYLLrqLyOOkuE%3D” Content-Type: application/xml Content-Length: 277 “

    • I read a lot on yahoo doc but don’t fix it. Below is code:
      function call_yql($consumer_key, $consumer_secret,$guid, $querynum, $access_token, $access_token_secret, $usePost=false, $passOAuthInHeader=true)
      {

      $url = ‘http://query.yahooapis.com/v1/yql’;
      $params[‘q’]=”INSERT INTO social.updates(guid,title,description) VALUES (me,’duoc’,’abc’)”;
      $params[‘format’] = ‘json’;
      $params[‘callback’] = ‘cbfunc’;
      $params[‘oauth_version’] = ‘1.0’;
      $params[‘oauth_nonce’] = mt_rand();
      $params[‘oauth_timestamp’] = time();
      $params[‘oauth_consumer_key’] = $consumer_key;
      $params[‘oauth_token’] = $access_token;
      // $params[‘debug’] = true;

      // compute hmac-sha1 signature and add it to the params list
      $params[‘oauth_signature_method’] = ‘HMAC-SHA1’;
      $params[‘oauth_signature’] =
      oauth_compute_hmac_sig($usePost? ‘POST’ : ‘GET’, $url, $params,
      $consumer_secret, $access_token_secret);

      // Pass OAuth credentials in a separate header or in the query string
      if ($passOAuthInHeader) {
      $query_parameter_string = oauth_http_build_query($params, true);
      $header = build_oauth_header($params, “yahooapis.com”);
      $headers[] = $header;
      } else {
      $query_parameter_string = oauth_http_build_query($params);
      }

      // POST or GET the request
      if ($usePost) {
      $request_url = $url;
      logit(“call_yql:INFO:request_url:$request_url”);
      logit(“call_yql:INFO:post_body:$query_parameter_string”);
      $headers[] = ‘Content-Type: application/x-www-form-urlencoded’;
      $response = do_post($request_url, $query_parameter_string, 80, $headers);
      } else {
      $request_url = $url . ($query_parameter_string ?
      (‘?’ . $query_parameter_string) : ” );
      logit(“call_yql:INFO:request_url:$request_url”);
      $response = do_get($request_url, 80, $headers);
      }

      // extract successful response
      if (! empty($response)) {
      list($info, $header, $body) = $response;
      if ($body) {
      logit(“call_yql:INFO:response:”);
      print(json_pretty_print($body));
      }
      $retarr = $response;
      }

      return $retarr;
      }

      I use post to execute sql.

      Current it don’t work. Please help you fix it. Thank a lot.

  27. the 3rd step (Authenticate the user and get the user authorization for your application) redirects me to yahoo login page.can i do the authorisation without giving my yahoo credentials

    • If your call to yahoo is to get non-public user data, then the user must authorize your application first.
      Once the user authenticates to yahoo and authorizes your app, then you can store the access token and secret in some persistent store and reuse it repeatedly, without having the ask the user to do anything again.

  28. Great! but how can I sign out the user to clear the session? If there’s another user wants to login, it will not ask the user to put any user and password data because the session is still accessible.

    • Your application needs to handle session management correctly. OAuth issues aside, if the user wishes to “logout”, you simply forget/throw away all the data associated with the session, which in the case of OAuth, would be the session token, secret, etc.

      • Then can I handle multiple session in my yahoo app? I want that if another person wants to login to my yahoo app, then it should have a different session to yahoo not the previous one.

  29. Hi ,

    Nice article really helpful.I have followed each steps and got the result.But my doubt is,if the session expires i need to follow all the steps or just need to start from steps 5?

  30. Hi,

    I need a help from you.I want to retrieve all plaayers data including thier points,status etc from yahoo fantasy api.For that is this, ‘select * from fantasysports.players where game_key=257’ correct query?

  31. I did something really stupid that cost me an hour of my life so I thought I’d post my mistake in case anybody else has this problem.

    When getting an OAuth Consumer Key and Secret you’ll notice that the Consumer Key has … at the end of it.

    I copied and pasted that whole string with the … at the end. This is wrong. The … means there are more characters they aren’t showing you.

    If you click the number the whole string will appear. THAT is the full key you want to use. Ouch.

  32. Pingback: Yql Console | TagHall

    • I think you have your encode/decode of your signature key mixed up. You have to encode your consumer secret and token secret. Try running through the example php scripts one step at a time, and see what it prints out to the screen.

  33. Hey there, I’m getting “Call to undefined function refresh_access_token()” in the refacctok.php script. Any hints as to why?

      • Nope, I was actually thinking something changed from the examples and what I’ve downloaded. But, I ended up figuring it out. The very first set of lines:

        //refresh_access_token(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET,
        // $old_access_token, $old_token_secret,
        // $oauth_session_handle, false, true, true);
        //if (! empty($retarr)) {
        // list($info, $headers, $body, $body_parsed) = $retarr;
        // if ($info[‘http_code’] == 200 && !empty($body)) {
        // print “Use oauth_token as the token for all of your API calls:\n” .
        // rfc3986_decode($body_parsed[‘oauth_token’]) . “\n”;
        // }
        //}

        needed to be commented out (as shown). After I commented those lines out, everything worked as expected. I’d be interested in getting with you on figuring out why/why not commenting those lines out worked. No one online (that I found – but I looked around quite a bit) offers help on refreshing Yahoo’s token besides yours. You have single-handedly helped me finish my site. If you don’t see my email address, let me know. I’d be happy to tell you.

        Thanks!,
        Matt

  34. It’s so great to see this sharing! But I have one question. Since it fetches default 5 counts of contact, do you know how to change this value so that i can get any count of contact?
    Thanks.

    • In line 33 of the callcontact.php script, you should see the url being formed. Look for the “count=5”. You can change this 5 to be another number of the special keyword max, e.g. count=10 or count=100, or count=max. If you have many contacts, count=max may take a long time to return or timeout completely.

  35. Hello – I’ve run through everything but one error is constant:

    “( ! ) Notice: Undefined variable: argv in php on line 10
    Call Stack
    # Time Memory Function Location
    1 0.0013 391432 {main}( ) ..\getreqtok.php:0
    2 0.0026 449824 require( ‘C:\wamp\www\OAuthI\globals.php’ ) ..\getreqtok.php:2

    I can’t figure out why – any thoughts?

  36. So remove the line of code “$progname = $argv[0];” from the globals.php file and additionally disable notices, if desired.

    Unrelated, but I changed port from 80 -> 81 throughout the files. A search-and-replace will make sure you got all of the instances. Just a tip for the folks on Windows using Skype.

    Joe – this is excellent and the work you did here is very helpful. Thank you.

  37. Hi,
    I get a request token perfectly.
    The user its authenticated and get the user authorization too, but when the user agree to share contacts, the system always returns the following error although the data are correct.

    Array ( [oauth_problem] => token_rejected )

    I have been looking for information before disturbing here but no one has known me.
    I would appreciate any help.

    Regards

    • Are you using these scripts or are you running into problems with your own oauth code. Run the scripts and compare the output of what it sends vs your own program’s output. The problem will usually be with the signature generation step.

      • Thanks Joec,

        I had a failure beginner, my callback will be designated getreqtok.php and overwrote same keys.

        Thank you very much for everything, you’ve been very helpful

        Regards

  38. hello joec , i am using yahoo oauth api to access yahoo contacts list what dialog box display with following message.

    Allow this application to access your Yahoo! account?
    With your permission, this device or software application from a third-party publisher can use the data in your Yahoo! account. Enter the code that was provided to you by the device or application.
    what is this 7 digit code.

  39. Thanks for reply.
    yes i get the code attached at the end of url. but it require manually fill the code in the box .its not user friendly .
    any alternative for this.after filling the code user grant page display and then in last step it give the error signature not valid.
    i followed your code.
    my code is to get contacts after successfully going through three loop.
    function callcontact($consumer_key, $consumer_secret, $guid, $access_token, $access_token_secret, $usePost=false, $passOAuthInHeader=true)
    {
    $retarr = array(); // return value
    $response = array();

    $url = ‘http://social.yahooapis.com/v1/user/’.$guid.’/contacts;count=5′;
    $params[‘format’] = ‘json’;
    $params[‘view’] = ‘compact’;
    $params[‘oauth_version’] = ‘1.0’;
    $params[‘oauth_nonce’] = mt_rand();
    $params[‘oauth_timestamp’] = time();
    $params[‘oauth_consumer_key’] = $consumer_key;
    $params[‘oauth_token’] = $access_token;

    // compute hmac-sha1 signature and add it to the params list
    $params[‘oauth_signature_method’] = ‘HMAC-SHA1’;
    $params[‘oauth_signature’] =
    Helper_yahoo::oauth_compute_hmac_sig($usePost? ‘POST’ : ‘GET’, $url, $params,
    $consumer_secret, $access_token_secret);

    // Pass OAuth credentials in a separate header or in the query string
    if ($passOAuthInHeader) {
    $query_parameter_string = Helper_yahoo::oauth_http_build_query($params, true);
    $header = Helper_yahoo::build_oauth_header($params, “yahooapis.com”);
    $headers[] = $header;
    } else {
    $query_parameter_string = oauth_http_build_query($params);
    }

    // POST or GET the request
    if ($usePost) {
    $request_url = $url;
    logit(“callcontact:INFO:request_url:$request_url”);
    logit(“callcontact:INFO:post_body:$query_parameter_string”);
    $headers[] = ‘Content-Type: application/x-www-form-urlencoded’;
    $response = do_post($request_url, $query_parameter_string, 80, $headers);
    } else {
    $request_url = $url . ($query_parameter_string ?
    (‘?’ . $query_parameter_string) : ” );
    Helper_yahoo::logit(“callcontact:INFO:request_url:$request_url”);
    $response = Helper_yahoo::do_get($request_url, 80, $headers);
    }

    // extract successful response
    if (! empty($response)) {
    list($info, $header, $body) = $response;
    if ($body) {
    Helper_yahoo::logit(“callcontact:INFO:response:”);
    print(Helper_yahoo::json_pretty_print($body));
    }
    $retarr = $response;
    }

    return $retarr;

    }

  40. Hi Joec, I tested the script, but I get always this error from Yahoo : “signature_invalid: The signature provided does not match the one calculated by the service.”
    What could be the issue? … Thanks in advance for for your help.

    Here is the complete error:

    { “error”: { “lang”: “en-US”, “description”: “Please provide valid credentials. OAuth oauth_problem=\”signature_invalid\”, realm=\”yahooapis.com\”” } } array(3) { [0]=> array(20) { [“url”]=> string(104) “http://social.yahooapis.com/v1/user/53EXDL2O6OKVFYAGSTI75JWYYQ/contacts;count=5?format=json&view=compact” [“content_type”]=> string(16) “application/json” [“http_code”]=> int(401) [“header_size”]=> int(391) [“request_size”]=> int(1337) [“filetime”]=> int(-1) [“ssl_verify_result”]=> int(o) [“redirect_count”]=> int(o) [“total_time”]=> float(0.593335) [“namelookup_time”]=> float(0.43243) [“connect_time”]=> float(0.490941) [“pretransfer_time”]=> float(0.490944) [“size_upload”]=> float(o) [“size_download”]=> float(143) [“speed_download”]=> float(241) [“speed_upload”]=> float(o) [“download_content_length”]=> float(-1) [“upload_content_length”]=> float(o) [“starttransfer_time”]=> float(0.593139) [“redirect_time”]=> float(o) } [1]=> string(391) “HTTP/1.1 401 Authorization Required Date: Thu, 28 Nov 2013 18:35:48 GMT Cache-Control: private WWW-Authenticate: OAuth oauth_problem=”signature_invalid”, realm=”yahooapis.com” Vary: Accept-Encoding Content-Type: application/json Age: 0 Transfer-Encoding: chunked Connection: keep-alive Via: http/1.1 r03.ycpi.ams.yahoo.net (ApacheTrafficServer/4.0.2 [cMsSf ]) Server: ATS/4.0.2 ” [2]=> string(143) “{“error”:{“lang”:”en-US”,”description”:”Please provide valid credentials. OAuth oauth_problem=\”signature_invalid\”, realm=\”yahooapis.com\””}}” }

  41. My Yahoo Oauth API is working fine upto last week , but now its getting an error like ,
    stdClass Object
    (
    [error] => stdClass Object
    (
    [lang] => en-US
    [description] => Please provide valid credentials. OAuth oauth_problem=”signature_invalid”, realm=”yahooapis.com”
    )
    Do you have any idea ?

  42. Hey, great article! I’m having the OST_OAUTH_SIGNATURE_INVALID_ERROR problem as well, but I’m not sure what you mean in the article (and comments) about “check your Signature Base String normalization code”. I am using your code virtually word-for-word just to try and get up and running – so what tweaking/checking would this need from the code you provided? What could be different in my local environment that would cause this not to work, considering it’s all vanilla code? Have tried turning the HMAC-SHA1 off and on, but I’m getting the same result. Have done a heap of research but can’t seem to find any solution for this…any help would be much appreciated!

    • Nevermind, it was me not copying & pasting code properly. Wasn’t calling rfc3986_decode() on $body_parsed[‘oauth_token’] in getacctok.php. Solved. Thanks for all the help!

  43. Hello.

    Great tutorial, Joec! Everything worked fine until a while back when suddenly, I was editing the code in callcontact.php to suit the layout on my site and Yahoo started displaying this message to me as a response from callcontact.php instead of json data:

    Will be right back… Thank you for your patience. Our engineers are working quickly to resolve the issue.

    I get the above message’s parent web page code (ie HTML code) and not json data. I don’t understand what went wrong. As far as I know, i haven’t edited anything in my file with respect to the API’s working. I’ve been manipulating the layout and parsing the resultant json information.

    Really hoping you can help me with this.

    Thanks in advance!

  44. Necroposting here, but I’m receiving a Session Expired error when attempting to pull the contacts list (using the PLAINTEXT method via https url).

    Any ideas?

  45. I’m trying to insert that into my web app and by now all are functional. The only thing is wrong, passed the authentication, is the callcontacts.php that is saying:

    Not Found on Accelerator: social.yahooapis.com
    Will be right back…
    Thank you for your patience.
    Our engineers are working quickly to resolve the issue.

    What is this? Is not working at all?

    • you should change “http” to “https” in callcontact.php where is:
      $url = ‘http://social.yahooapis.com/v1/user/’ . $guid . ‘/contacts;count=5’;

      but I did it and it didn’t work for me
      if it work for you please reply

  46. Thanks for the script. I would have never been able to do it without it. However I had to change from http to https _and_ the port from 80 to 443. Now I finally get the contacts…

  47. Hi,

    I am getting error while getting the yahoo profile.
    {“error”:{“@lang”:”en-US”,”@uri”:”http://yahoo.com”,”description”:”Please provide valid credentials. OAuth oauth_problem=\”OST_OAUTH_SIGNATURE_INVALID_ERROR\”, realm=\”yahooapis.com\””,”detail”:”Please provide valid credentials. OAuth oauth_problem=\”OST_OAUTH_SIGNATURE_INVALID_ERROR\”, realm=\”yahooapis.com\””}}

    why it is giving this error.I am using the same procedure specified https://developer.yahoo.com/oauth/guide/oauth-make-request.html site.

  48. Joec
    Can you please solve the last step problem?
    seems that it is because of changing http to https from Yahoo!, but it will display nothing for me!
    can you please check “callcontact.php”

    thanks a lot

    • Hi Reza,

      Reader Alex (from 3 months ago) writes that changing the port to 443 in addition to changing the scheme from http to https works. I’ll update these scripts when I get the chance.

      • yes, I test it and it work correctly right now

        Thanks A lot for your fast reply
        Your tutorial is so useful

        Thanks man

  49. How can I take this a step further in YQL and make it check for the expired token AND THEN pull the new token/secret? I’m so close to finishing my project thanks to this tutorial.

    • You can handle token expiration by handling invalid token (and attempting to do the refresh), or keep track of the token expiration by a timer and then preemptively doing a token refresh. You can *always* refresh a token every time before you make the API call, but then you would be doubling the number of API calls for no good reason.

  50. At step 2 i get empty page, I made everything as written, i guess.
    Maybe I made a mistake,
    I changed OAUTH_CONSUMER_KEY and OAUTH_CONSUMER_SECRET, tried to change $debug, tried varying the $useHmacSha1Sig variable.
    and nothing empty page…
    Please help.

    • Step 2 is supposed to be run on the command line. In fact all steps (except for step 3), must be run from the command line. Therefore, getting an “empty page” makes no sense.

  51. Really like your simple and straight guide. It would help me make more complicated and PROD like code. Just a few comments (I run the sample in browser)
    – $progname => you guys may want to comment it
    – oauth_helper.php line 151….
    – https vs http
    – etc…
    Well people have fixed it but the author has not updated the source code.
    Again, thank you very much

  52. awesome info here unfortunately I am a bit stuck on step 4, getting errors and not sure what is going wrong keep getting token rejected, works up until step 4 at which point I am extremely confused as to what inputs go into the getaccotok file, is the request token the same as what I put into globals.php or am I supposed to put something else in there for token and secret? I go to the url and authorize the app in step 3, do I put the code that generates in as verifier? its all way confusing to me.

  53. Is it normal to get this output when executing the callcontact.php script?

    $ php callcontact.php
    PHP Notice: Undefined index: port in /home/wilfried/www/private/bundle_try/oauth_yahoo/oauth_helper.php on line 151

    Notice: Undefined index: port in /home/wilfried/www/private/bundle_try/oauth_yahoo/oauth_helper.php on line 151
    +++2015-07-28T10:49:44-0400:signature_base_string:INFO:normalized_base_string:GET&http%3A%2F%2Fsocial.yahooapis.com%2Fv1%2Fuser%2FX4323GFSERGF43454GSFGBCCB3%2Fcontacts%3Bcount%3D5&format%3Djson%26oauth_consumer_key%3Drjfnfrioei49fekdi848w2ADRadfiAERSF234DDFAHGNF345dfasdffpoig34p5o6h7jCdTfSJzZWNyZXQmeE24ASe–%26oauth_nonce%3D316182831%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1438094984%26oauth_token%3DA%253DKdfjadlskfjSDFGG.ertklsioerkjhSDFGkjlhasdfik345k34897SDFgklhe4kljhdSGKLjhsdfg.mcxkhdfSGKHsdfgkjeroI.REsdFGSFDg.sdfgiwresdfgsfhg.gh.tyu.ghfj.dfghfsdg.fgsdg.sdfgiretkjsfdgkjlhertiuysdfgkjhsdfgkljertkjhsdfguyert8743508972345lkjhsdfi8g89sdfg89sdfg908sdfg897sdfg8sdfg734jk25kljhwdkjlhsdfgkjlhsfdgkjlhsdfgjkhsdfgkjhsfdgiuywert87425ksdkjhlsdfgkjlhsdfgjklcxbm.cxvb.asfdkljadsflk.jasldkj3452387wert98sdfg8sdfg897sdfg890sdfgpoiret.lsdfgkljsdfgiwret_sfgkjhmnsdfgjkcvbmsdfglkjhewrtiusdfgjkhsdfgiuret87245lkjhdsfg.mnvbkisdfwertrwt.42534wertwgsdfg.cxvbsfdgsdfg.rwetwert.452435wertwretwer.wertwergtsdfgsdfg.sdfgsdfgrewtwret4252345wtdfgsdfg.sdfgsdfgsdfgewrtwert23452345wertwgsdfgfdrtyfhdgsdfgsdfgrewtwertsdfgdfgrt2rwersdfgdfgretrwefgrwtwertwertweryrwywertwertfsgfsdgsdferw3452twresdfgwretwert45wrtertrtg-%26oauth_version%3D1.0%26view%3Dcompact
    +++2015-07-28T10:49:44-0400:callcontact:INFO:request_url:http://social.yahooapis.com/v1/user/X4323GFSERGF43454GSFGBCCB3/contacts;count=5?format=json&view=compact
    +++2015-07-28T10:49:44-0400:callcontact:INFO:response:

    Yahoo

    html {

    height: 100%;

    }
    body {

    background: #fafafc url(https: //s.yimg.com/nn/img/sad-panda-201402200631.png) 50% 50%;
    background-size: cover;
    height: 100%;
    text-align: center;
    font: 300 18px “helvetica neue”,
    helvetica,
    verdana,
    tahoma,
    arial,
    sans-serif;

    }
    table {

    height: 100%;
    width: 100%;
    table-layout: fixed;
    border-collapse: collapse;
    border-spacing: 0;
    border: none;

    }
    h1 {

    font-size: 42px;
    font-weight: 400;
    color: #400090;

    }
    p {

    color: #1A1A1A;

    }
    #message-1 {

    font-weight: bold;
    margin: 0;

    }
    #message-2 {

    display: inline-block;
    *display: inline;
    zoom: 1;
    max-width: 17em;
    _width: 17em;

    }

    document.write(”);





    Will be right back…
    Thank you for your patience.
    Our engineers are working quickly to resolve the issue.

Leave a reply to Karthik Cancel reply