OAuth: Under the Hood

This article was first published in the “From the Cloud” column in php|architect magazine.

Ever been asked for your username and password by a website that wants to access your data from another service? By all means, don’t give it to them! This month’s From the Cloud takes a look under the hood of OAuth to show how its request process protects users from ever having to give away their credentials again.

If you’ve ever used Twitter, Delicious, or any other service that has an API requiring your authentication credentials, you’ve likely encountered a situation in which a third-party website has asked for your username and password in order to gain access to your account through that API. These third parties often make claims like, “Don’t worry! We’re not evil, and we won’t steal your password.” These claims make me feel safe. About as safe as jumping from a plane without a parachute.

Luckily, representatives from organizations such as Twitter, Flickr, Six Apart, Magnolia, Jaiku, Google, and others have developed an open protocol to solve just this problem. These organizations know of this problem from first-hand experience, since they all provide APIs to their users’ data, and, since these APIs require authentication, they all need a method allowing the user to authorize third-party access to their data without giving away their credentials to the third party. Enter the OAuth protocol.

According to its specification, OAuth is an open protocol that “enables websites or applications (Consumers) to access Protected Resources from a web service (Service Provider) via an API, without requiring Users to disclose their Service Provider credentials to the Consumers.” You may implement OAuth as either a Consumer or a Provider, and there are tools that can help with the implementation. I’ll focus on the request process from the point of view of a Consumer, showing all of the requests and responses along the way in an effort to demystify the process.

The OAuth Process

At first glance, OAuth is an extremely complex process. One quick look at Figure 1 is all you need to see the complexity and the numerous requests and responses involved in authenticating a user. However, the complete OAuth process can be summed up in four simple steps:

Figure 1. OAuth Flow Diagram
OAuth Flow Diagram
  1. The Consumer requests a Request Token from the Provider (Step A)
  2. The user authenticates with the Provider (Step B)
  3. The Consumer requests an Access Token from the Provider (Step C)
  4. The Consumer retrieves the user’s protected data from the Provider (Step D)

Before we get started, there are a few terms to define. The Provider is an application that allows access to its API through OAuth. The user is a person who has an account with the Provider. The Consumer is a website or application using OAuth to access the Provider on behalf of the user. The Request Token is used by the Consumer to obtain authorization from the user. It is exchanged for an Access Token. The Access Token is then used by the Consumer to gain access to the user’s protected data on behalf of the user, rather than directly using the user’s username and password. The benefit is that the user never needs to give his or her username or password to the Consumer.

Getting the Request Token

The very first step in the OAuth process is initiated by the user. The user is the one who wants to use an application to access their data that exists on a third-party service. Reasons for why users may want to do this abound. Perhaps the application aggregates user content from various services, or maybe it mashes up user data in a particular way, providing a unique visualization of that data. Whatever service is provided, the user needs to grant the application access to their data, and that’s where OAuth comes in.

To discuss this process in detail, we’ll envision a fictional Consumer and Provider. The example that the OAuth documentation provides is that of a photo-sharing service as the Provider. So, following their example, suppose our application needs to request a user’s photos from a third-party service such as Flickr or SmugMug. For the sake of example, we’ll call this third-party photo sharing service FooPhoto (the Provider), a service for sharing photos, and our service MyFooLife (the Consumer), a service that aggregates users’ life stream data from various third-party services, including FooPhoto.

The first request made is that from the user’s client/browser to our service, identified here as myfoolife.example.com. Figure 1 represents this request as Step 1.

GET /mypictures HTTP/1.1
Host: myfoolife.example.com

When a user makes this request of our service, MyFooLife, to see their photos from FooPhoto, we must send a request in the background to FooPhoto to get a Request Token. The Request Token is the first part of this process and we’ll use it to obtain authorization from the user so that we may access their protected data at FooPhoto. Listing 1 shows the POST request we’ll make as the Consumer to the Provider to obtain the Request Token (see Step 2 in Figure 1).

Listing 1.
POST /oauth/getRequestToken HTTP/1.1
Host: foophoto.example.com
Authorization: OAuth realm="http://foophoto.example.com/",
oauth_consumer_key="myfoolife.example.com",
oauth_nonce="37c0712e605ff858f26211323adddcb3",
oauth_signature_method="RSA-SHA1",
oauth_timestamp="1234822009",
oauth_version="1.0",
oauth_signature="IgJbu19VwYBXyRAautunRRKfCfc2pD%2B3..."
Content-Length: 0

If all goes well and our OAuth parameters and sig- nature check out, FooPhoto will return a response including the oauth_token and oauth_token_secret parameters. This response is Step 3 of Figure 1.

HTTP/1.1 200 OK
Server: FooPhoto
Content-Type: text/plain; charset=UTF-8

oauth_token=4%2FPybRyrmTUbAqwU5A_eSrUQvwqJu5&oauth_token_secret=fs5sWCIWPmJKmhgNBpguFJ8C

User Authentication

Now that FooPhoto, has given us a Request Token—the oauth_token returned in the previous response—we may now redirect the user to FooPhoto so that they can authenticate with the service and grant MyFooLife access to their protected photos. We do this by send- ing a redirect response to the user, redirecting them to foophoto.example.org and including the oauth_token in the request. This response is represented by Step 4 in Figure 1.

HTTP/1.x 302 Moved Temporarily
Server: MyFooLife
Location: https://foophoto.example.org/oauth/authorizeToken?oauth_token=4%2FPybRyrmTUbAqwU5A_eSrUQvwqJu5&oauth_callback=http%3A%2F%2Fmyfoolife.example.com%2Fmypictures

Now the user is no longer on our application. They are viewing a page on the FooPhoto website asking them to either log in or, if they already have an active session, grant MyFooLife access to their protected data. Once this process is complete and the user has either granted or denied access, FooPhoto redirects the user back to MyFooLife using the oauth_callback parameter presented in the previous request. The Location contains the Request Token authorized or denied by the user. Step 5 in Figure 1 shows when this response occurs.

HTTP/1.x 302 Moved Temporarily
Server: FooPhoto
Location: http://myfoolife.example.org/mypictures?oauth_token=4%2FPybRyrmTUbAqwU5A_eSrUQvwqJu5

Requesting the Access Token

By now, the user has granted permission to MyFooLife to access their photos on FooPhoto. Using the Location header given in the previous response, the user’s browser now sends a request to MyFooLife, including the authorized Request Token. MyFooLife may now begin the process of obtaining the Access Token, which is what we will need to get the user’s protected data from FooPhoto. Step 6 represents this request.

GET /mypictures?oauth_token=4%2FPybRyrmTUbAqwU5A_eSrUQvwqJu5 HTTP/1.1
Host: myfoolife.example.com

Now, the magic occurs. This is the moment we’ve been waiting for. The next few series of requests and responses will provide our service with access to the user’s photos.

Listing 2.
POST /oauth/getAccessToken HTTP/1.1
Host: foophoto.example.com
Authorization: OAuth realm="http://foophoto.example.com/",
oauth_consumer_key="myfoolife.example.com",
oauth_nonce="91a851a9b2710d8a79d2a713a74c25a2",
oauth_signature_method="RSA-SHA1",
oauth_timestamp="1234822105",
oauth_token="4%2FPybRyrmTUbAqwU5A_eSrUQvwqJu5",
oauth_version="1.0",
oauth_signature="CVxQXHlgS7HaGHZFg68Kdjb8mYgY0fHBg..."
Content-Length: 0

In Listing 2 (and Step 7 of Figure 1), MyFooLife sends a POST request to FooPhoto to obtain an Access Token. As with the request to retrieve a Request Token, we include an Authorization header containing OAuth parameters verifying the origin of the request and including the Request Token, which we exchange for an Access Token. The Provider will verify the authenticity of the request and check whether the user has granted access to this Request Token. If all checks out, then the Provider returns a response containing the Access Token (Step 8).

HTTP/1.1 200 OK
Server: FooPhoto
Content-Type: text/plain; charset=UTF-8

oauth_token=1%2FEthgm-YklKKxp5IrWNbJ4A&oauth_token_secret=cWAo6%2Bhe4jduiZUEhaXcBhip

Accessing the User’s Data

MyFooLife now has the proper credentials to access the user’s photos. First, we got a Request Token, then the user granted access to their photos for that Request Token, and now we’ve exchanged the Request Token for an Access Token. It’s time to get the user’s photos and show them to the user.

While the previous requests will differ from service to service mainly in where the OAuth parameters are placed in the request—the Authorization header, the request body, or the query string—the next requests will depend on the service’s API, so they may be very different from what you see here, but the concept is still the same: we must send the Access Token along with all of the other OAuth parameters in order to authenticate our service with the Provider and retrieve the user’s data. Listing 3 shows an example of a request to get the user’s data from FooPhoto (Step 9). The Authorization header will look familiar, but this time, the oauth_token parameter contains the Access Token.

Listing 3.
GET /user/pictures HTTP/1.1
Host: foophoto.example.com
Authorization: OAuth realm="http://foophoto.example.com/",
oauth_consumer_key="myfoolife.example.com",
oauth_nonce="3f26a264e990a358612a0a4187be215f",
oauth_signature_method="RSA-SHA1",
oauth_timestamp="1234822717",
oauth_token="1%2FEthgm-YklKKxp5IrWNbJ4A",
oauth_version="1.0",
oauth_signature="YSRH5fbfmWEhLFMGAVYwOJwhWy8g..."

FooPhoto checks the authorization credentials and the Access Token and decides that MyFooLife may access the requested user’s data, and sends it back in the format requested by the Consumer and depending on the API of the service (Step 10).

HTTP/1.1 200 OK
Server: FooPhoto
Content-Type: application/xml; charset=UTF-8

{User's picture data}

MyFooLife now has the user’s photos and can send them back to the user, and that’s exactly what we do in Step 11.

HTTP/1.1 200 OK
Server: MyFooLife
Content-type: text/html; charset=UTF-8

Here are your pictures...

A View from the Cloud

So, that’s the OAuth request process in eleven simple steps. It is my hope that I’ve demystified the process, and that, while there are many different steps along the request cycle to gain access to a user’s protected data, they are necessary to provide security and shield the user from giving away their username and password to third-party websites.

OAuth is still new, having been finalized as OAuth 1.0 in December 2007, and people are just now beginning to talk about it and advocate its use. In fact, at the time of this writing, an OAuth working group is being formed with the Internet Engineering Task Force (IETF) for the purpose of producing one or more documents for consideration as an IETF proposed standard, otherwise known as an RFC. I’m certain we’ll begin to see more and more OAuth implementations as this year progresses, as well we should. Asking users to enter their username and password on a third-party website to access their protected data on another service is a horrendous practice that should be avoided at all costs. I hope that OAuth and similar authentication mechanisms will put an end to this practice once and for all.

To learn more about the OAuth protocol, including details on all the OAuth parameters and how to sign the requests, read the full protocol specification at http://oauth.net/core/1.0/.

For More Information