Skip to content

API

When OAuth Goes Wrong: Debugging Signature Mismatch Issues in PHP

OAuth is all the rage. Unfortunately, OAuth also produces a lot of rage. With major sites like Twitter, Facebook and LinkedIn moving towards OAuth authentication, more developers are climbing the OAuth learning curve so that they can integrate these services into their own applications. Unfortunately, even when you understand the basics of OAuth, getting it to work is a whole other matter.

The most common OAuth error is the signature mismatch, which occurs when your application and the server calculate different signatures for a signed OAuth request. I recently tackled OAuth while writing API documentation for a client (can you see the scars?), and stumbled across some great tools and tricks that can make the ordeal a little less painful.

But only a little.

(This article assumes you know the basics of OAuth. If not, don’t worry – we’ll cover some of the fundamentals in another article soon.)

What Causes a Signature Mismatch

Unless an OAuth-enabled API supports the signature method PLAINTEXT, all calls to OAuth APIs must be signed using a shared secret. What gets signed is a chunk of text called the Signature Base String (SBS), a strict, reproducible concatenation of HTTP request elements. The structure of the SBS is specified in RFC 5849, Section 3.4, and consists of:

  • The HTTP request method, followed by an ‘&’ character.
  • A canonicalized base string URI, specified in RFC 5849 Section 3.4.1.2, followed by an ‘&’ character.
  • A list of the request parameters included in either the GET or POST request, sorted alphabetically, as specified in Section 3.4.1.3.2.

If the client application and server do not agree exactly on the composition of this string, they will produce different request signatures, causing the server to reject your request.

Use a Public Library

First things first: all other things being equal, you should consume OAuth using one of the freely available third party libraries, as opposed to rolling your own OAuth client code. Most of these libs have been extensively tested, and are in production use around the world. This will greatly reduce, if not eliminate, the odds that some OAuth implementation bug is causing your requests to fail. OAuth.net maintains an evolving list of available libraries for various platforms.

If you’re developing on PHP,  a great option is Andy Smith’s oauth-php library. Andy’s library is solid and tested. Plus, it’s written as a set of PHP files as opposed to a PHP extension, which means it can be used painlessly on virtual hosting accounts. It also means you can hack in debug statements all over the place, and get some insight into how OAuth ticks. Score!

(Code tip: For oauth-php, the method for calculating the SBS, signatureBaseString(), is in a file named OAuthRequest.php. You can echo out this string before it’s returned to see how oauth-php calculated your SBS.)

Check Your Server Time

OAuth uses timestamps in requests as part of its design to prevent replay attacks against a server. If your server or client’s system clock differs from the API host’s time by more than several minutes, the OAuth API is likely to reject your request. If you’re experiencing a signature mismatch issue, synchronize your system clock with a network time server, and try your requests again.

Check Your Parameters

Did you spell all of the query string or POST body parameters correctly in your request? Did you include any parameters that may not actually be used by the server for this particular method call? A simple misspelling of a parameter name can cause a signature mismatch – as I found out when I spelled a query string parameter as comment, only to find out the the actual value was comments. D’oh!

A frequent stumbling block between client and server implementations of OAuth is the number of times a component is URL-encoded. A careful reading of the OAuth specification shows that most of the components – including the URL and the request parameters – are URL-encoded twice. So a space character in a query string parameter value will appear in the SBS, not as %20, but as %2520.

Spaces in particular can be a headache for developers who use URI parsing libraries to obtain input parameters from environments such as Python and Ruby. Some parsing libraries like to substitute all spaces in query string parameter values with a ‘+’ sign, which could cause your client and the OAuth service provider to calculate the SBS differently. Using a tool like Netflix OAuth Test (discussed below) can help you debug these problems in your client code.

Calculate The SBS Using a Third-Party Interface

If you’re using an OAuth API from Google, Flickr, or one of the other big bulls of the Web, odds are slim that they’ve goofed on their implementation. If you’re using a new API, however, the provider may still have a glitch or two to work out. OAuth is hard to get right, and there’s no guarantee that the service you’re using has implemented it correctly.

If you’re using a third-party library, and the obvious components (request method, URL, query string parameters) look good, try calculating the SBS using a known good implementation of the OAuth signature algorithm. My favorite is the OAuth Test form from Netflix. It supports calculating an SBS for any service, not just the Netflix API.

Make sure to enter your parameters and query string unencoded; the tool will take care of  all necessary encoding. If your SBS and the SBS generated by Netflix agree, odds are there’s an error in the server. Contact the service provider, and work with them on debugging the problem.

Be Sociable, Share!
    The following two tabs change content below.

    One Comment (Add Yours)

    1. I want to thank you almost 1 year after you wrote this for pointing me to the netflix tester, and also for making a mention of not encoding things the proper amount of times.

      In fact my final problem was this: instead of having key->value pairs encoded correctly for SBS ——

      encode(key)+’=’+encode(value)

      I had done this:

      encode(key+value) such that the ‘=’ was encoded twice along with the rest of the string (this made sense to me!)

      And thank you also for taking such a disdainful tone toward the signature generation process. It has been a royal pain in my ass for about 24 hours. I think I dreamt of it last night. For all the massive amounts of specifics in the oauth documentation, it’s really not specific enough.

    Add Your Comment (Get a Gravatar)