OAuth 1 Client

Our deep dive into the functionality of OAuth will begin by looking at the client for OAuth 1. The term client has a lot of different contexts, but in this context we’re referring to any program able to make a valid OAuth request. The client has the responsibility of first properly identifying the user trying to request a protected resource. Since we’re using OAuth to avoid having to pass our credentials around the Internet, it’s important to understand verifying an identity is more complex than a simple username/password combination.

Learning how to make OAuth requests allows you to interact with more services and build a more robust, integrated user experience in your application. If you are planning to build an API, understanding how the requests are made will give you valuable insight on what to look for when validating them. This chapter is going to focus on some of the core concepts in building an OAuth request, namely, the signature, the nonce, and tokens. Figure 3.1 shows the flow of requests in OAuth 1.0.

Figure 3.1
Figure 3.1

Components of an OAuth 1 Signature

As you’ve seen in the preceding chapters, we will use HTTP Headers to identify our clients to a server. Before proceeding, you should be familiar with the concepts in Chapter 1, specifically with how HTTP Headers work. While that chapter will not make you an HTTP expert, it provides enough information and concepts needed to understand this chapter.

The header we’re going to be paying particular attention to is the Authorization header. This header must be constructed correctly for an OAuth Server to be able to work with our requests. The Authorization header contains all the pertinent information needed to identify ourselves to the third-party service our client is trying to access. The Authorization header has a number of different components we will look at in detail. Knowing these will help you understand how to generate and use the components to create a valid OAuth request.

Let’s get started by taking a look at the components of the Authorize header needed to create an OAuth Request. We’ll start at the simple items and then move on to the more complex ones.

Version

Version is quite simply the version of OAuth you are trying to make a request against. Keep in mind the server you’re trying to access will determine what value you should use here. Most services will tell you in the documentation what version of OAuth is supported. From that point on, it’s up to you to set the version item in the header to the same version the server expects.

Timestamp

The timestamp is another pretty straight-forward value; it’s the time you are making the request. In other words, most likely “right now”. The value of timestamp is accepted as the number of seconds since the Unix epoch, so you don’t have to do any sort of date formatting. In PHP, the time() function will give you the number of seconds since the Unix epoch. It can be safely utilized to create the timestamp you will use for the request.

Callback

If your request is supposed to do something after the request is made, you can provide a callback. A callback is the URL you expect to be directed to once the request is completed. The most common example is authenticating against a third party service. Once the authentication process happens, tokens are exchanged by redirecting you to the callback. From there, the tokens can be retrieved and stored or cached so other requests can be made with those tokens.

Signature Method

When you are ready to sign your request, you need to tell the OAuth Server how you signed it by specifying the Signature Method. There are three different options: HMAC-SHA1, RSA-SHA1, and Plaintext. This tells the server how it should attempt to parse and verify the signature. The use of Plaintext is generally not recommended, since no attempt is made to protect the information from man-in-the-middle attacks. If you must use Plaintext, it should only be used over TLS or SSL as they will encrypt the contents of the signature.

Token

The token is a value you retrieve from the third-party service you are using and it is used to identify you. When you authenticate to a service with your username and password, the service hands out tokens identifying you in future calls. Unlike username and password combinations, these tokens are created in a way to change somewhat regularly. The token in the Authorization header is used to identify you, but it is not the token secret or a combination of the 2 keys.

Consumer Key

The consumer key is a value identifying what application on the third party you are trying to access, and is also handed out by the server. Services provide the ability for a developer to determine the resources API users can access and the level of access they have to those resources. To execute this, many services require you to create or register an API application through their developer portal. The registered application identifies whether the API should be use for read or read/write access, and in some cases, which resources are accessible through the API. Upon creation of this application, the server responds with a key & secret pair known as the Consumer Key and Consumer Secret. The consumer key is sent in the Authorization header and identifies the application, ensuring the server can issue responses in accordance with the settings of the API application.

Nonce

A nonce is a string that will not be used more than once in a reasonable amount of time. It’s used as a protection against replay attacks. Any request made with a nonce which has been used recently will be rejected by the server. This prevents attackers from reissuing the same request. Since the nonce is part of the signature, the signature must be regenerated with a new nonce to correctly re-sign a new request.

Signature

The signature is where all these important pieces of information are combined and encrypted. It allows the server to determine who you are and protects your credentials from being read in plain-text. Later in the chapter we’ll see the process for generating this signature in OAuth 1.0. For now, a simple overview will suffice.

Understanding Tokens

In the last section I introduced the concept of tokens, in this section we are going to explore them in depth. Tokens are used to identify a user or application to the OAuth server. Using tokens to identify a user eliminates the need to provide a username and password in the API call.

The tokens come in pairs, one part being a public token and the other a secret token. As the name implies, the secret token is to be kept a secret and is not transmitted with OAuth requests. Since both tokens are required to properly identify a user and the public access token is more easily discovered, it’s very important to protect the secret key and store it securely.

Securing tokens can be achieved with a couple simple practices. The first practice is to avoid committing the values of the key, token, and secrets to your version control system. Even if you are using a private repository, there is no way of knowing whether the repository will remain private, so it’s best practice to avoid committing the values. The second practice is avoid storing any files with these values in a publicly accessible location. If the values can be accessed through a web browser or through local storage in a browser, an attacker may be able to find these values and make requests on your behalf. Lastly, while you have to send the access token and consumer key in the Authorization header, it’s important to never send the secret values in plain-text via an HTTP Request. Later in this chapter we’ll be covering the composite key and its role in protecting the secret values from being sent in plain-text. I have found phpdotenv1 to be a great method of storing these values.

Tokens are provided by the third party service when a user authenticates and grants permission for the application to access their information. The service will essentially “connect” the local user account to the tokens. Since we have the ability to grant access to the API application, we also have the ability to revoke access. The application is identified by a different public/secret token combination which allows you to manage what applications have access to your account on the third party service. This is also the mechanism which allows for the revocation of applications.

The other important concept to understand with tokens is they are designed to have a relatively short life. Tokens are regenerated with each authentication call, so if the tokens aren’t maintained by the application using them, they will be new for each session. It is generally a good idea to take advantage of this characteristic, as it provides an additional layer of security for your account. Think of it as changing your password before every single login–that’s essentially what is happening and it makes it more difficult for attackers to fixate on an account. While there are still the same concerns with the account on the third party service, it helps prevent your information from being compromised by another application or API. It is very important to use strong passwords and utilize secure practices for storing your credentials regardless of how they are being used.

Understanding the Signature

The most difficult aspect of making an OAuth request is signing the request. If this step is done incorrectly, it will cause any HTTP request sent to the API to be rejected with a 401/Unauthorized status. Another confusing aspect is certain services require the components of the Authorization header to be in alphabetical order (Twitter, for example) while other services don’t require any particular order. This can be especially confusing when trying to make a request for the first time. Ideally, you should understand exactly what the OAuth server is expecting to receive, but it’s usually safe to alphabetize the components by default. That way, your client generates requests any service will accept.

There are a few sub-components of the signature we’ll want to define because they are vital to properly signing the requests. Understanding how these are generated will provide a better understanding of how all tokens and components of the Authorization header are used.

Base String

The Base String is a key component to building the signature. It contains different pieces of information delimited by the & character. Let’s take a look at how this component of the signature should be generated.

HTTP Verb

The first piece of this component is the HTTP verb being used for the specific request. Of the HTTP verbs introduced in Chapter 1, the verbs we’re most concerned with are DELETE, GET, POST, and PUT. Since every service is different, it’s important to understand what verb is expected for each endpoint. The other important thing to remember is the verb should always be in all capital letters. For example, if you are making a GET request, the first piece of this component should be GET and not Get or get.

Resource URL

The second component of the base string is the resource URL, which is simply the endpoint you are trying to access. This should be URL encoded as well so all the special characters in the URL are identified by their ASCII code. It’s recommended to use rawurlencode to encode this value. There isn’t much else to this piece, other than to note it should be delimited by an ampersand.

Authorization Header Components

Finally, we need to append all the information from the Authorization header to this string, separating each key/value pair by an ampersand. These should also be URL encoded and while the specification states they should be in alphabetical order, some services don’t actually require this. To avoid confusion, it’s a good practice to always sort them alphabetically. Let’s take a look at how we’d do this with a practical example, see Listing 3.1.

Listing 3.1

<?php
// values for all the headers
$authorization_header_values = [
    'oauth_nonce' => $nonce,
    'oauth_callback' => $callback,
    'oauth_signature_method' => 'HMAC-SHA1',
    'oauth_timestamp' => time(),
    'oauth_consumer_key' => $consumer_key,
    'oauth_token' => $token,
    'oauth_version' => '1.0'
];

// if there is no callback, don't send it
if (!isset($callback) || $callback === '') {
    unset($authorization_header_values['oauth_callback']);
}

// build the base string and sort the
// authorization header values alphabetically by key
$temp_array = array();
ksort($authorization_header_values);
foreach ($authorization_header_values as $key => $value) {
    $temp_array[] = $key . '=' . rawurlencode($value);
}

// unpack the values that we stored in the temporary array
$parameters = rawurlencode(implode('&', $temp_array));

As you can see, we build these last components similar to how a URL query string is constructed. Each key/value pair is denoted key=pair and each pair is delimited by an ampersand. You can also see by using ksort we’re able to alphabetize these components by key name.

Looping through the parameters as we did in Listing 3.1 provides an explicit look at what happens with each parameter. It is possible to use http_build_query to generate the base string, Listing 3.2 is an example of how to do it with the proper encoding. Keep in mind, there are differences in how each service implements the base string so one script may not cover all use cases.

Listing 3.2

<?php
// values for all the headers
$authorization_header_values = [
    'oauth_nonce' => $nonce,
    'oauth_callback' => $callback,
    'oauth_signature_method' => 'HMAC-SHA1',
    'oauth_timestamp' => time(),
    'oauth_consumer_key' => $consumer_key,
    'oauth_token' => $token,
    'oauth_version' => '1.0'
];

// if there is no callback, don't send it
if ($callback === '') {
    unset($authorization_header_values['oauth_callback']);
}

// build the base string
$temp_array = array();
ksort($authorization_header_values);

$parameters = rawurlencode(http_build_query($authorization_header_values));

Putting It All Together

So by using the example in Listing 3.1 and combining the results from the script with other components, we can build the base string. Let’s assume we’re making a GET request to https://example.org/user/bce123df4a, which will be stored in the variable $endpoint, and the output from the script in the listing is assigned to a variable $parameters. To build the base string we’d simply concatenate the values like so.

$base_string = 'GET&' . rawurlencode($endpoint) 
             . '&' . $parameters;

It’s important to note, since we URL encoded the parameters in the script, we don’t need to do it again here. Now we have the first component of our signature constructed and can move on to the next step.

This section will conclude with an example of a complete base string which was generated for a Twitter API request. (Note all keys and tokens in this request are not active and cannot be used to make a request).

GET&https%3A%2F%2Fapi.twitter.com%2F1.1%2Fstatuses%2F
user_timeline.json&count%3D2%26oauth_consumer_key%3D
Ruk5McRjIKd2DP22n3afjw%26oauth_nonce%3Dd303edff00aaaad160688
d8acab54bc6%26oauth_signature_method%3DHMAC-SHA1%26
oauth_timestamp%3D1445350048%26oauth_token%3D162aaaaa-yZJSlF
ednBab8zFJDZvSQ9AEDicAW2aHKcaHiBUaJ%26oauth_version%3D1.0%26
screen_name%3Dtwitterapi

The output above has been wrapped for display in this book. In reality, it’s a single, continuous string.

Composite Key

The Composite Key makes use of the secret keys assigned to the user (Consumer Secret) and the application (access secret). This step is more straight-forward and quite simply the Composite Key is hashed with the base string according to our signature method.

Simply put, to generate the composite key all we need to do is URL encode each key separately and delimit them with an ampersand. The Consumer Secret is first and the access secret comes next. Let’s assume our Consumer Secret is stored in $consumer_secret and the Access secret is stored in $access_secret. We end up with an implementation which looks something like this:

$composite_key = rawurlencode($consumer_secret) . '&' .
                 rawurlencode($access_secret);

Hashing the Signature

Now that we have a properly generated base string and composite key, the final step in the process is to hash them according to the signature method we’ve provided. It’s important the method we specify and the manner in which we hash the values are the same. We’re essentially telling the OAuth server how we created the signature so it knows how to validate our request. To demonstrate this quickly, we’ll assume the base string is stored in $base_string and the composite key is stored in $composite_key. If we specified SHA1, our hashing implementation will look like:

$signature = base64_encode(
   hash_hmac('sha1', $base_string, $composite_key, true)
);

As you might have noticed from Listing 3.1, we don’t have a component for the signature. Now that we have a signature, it should be pretty easy to set it in the Authorization header. We just need to make sure we create a key called oauth_signature and assign the value of the key to the value of $signature we just generated. Once it is added to the Authorization header, the request can be sent and should validate properly by the OAuth server.

Understanding the Nonce

We have familiarized ourselves with tokens and understand how to build the OAuth signature, but there still might be a word that looks unfamiliar. What exactly is a nonce? According to Webster’s Dictionary it is “a word or expression coined for or used on one occasion”. In the programming world, we’d call it a string and the rest of the definition fits the bill. It’s a string which is passed along with the request and is only used once. This means that every single request you send has a unique, unpredictable nonce.

In practice, this is a randomly generated hash and it’s used to protect from replay attacks. So while the word looks funny, there’s really not much to it. All you really need to remember is you shouldn’t use the same nonce value more than once.

To generate a nonce we need to generate a random string of characters and then hash them. There are some different techniques for doing this, below is one example.

$bytes = openssl_random_pseudo_bytes(16);
$string = bin2hex($bytes);
$nonce = hash(sha512, $string);
var_dump($nonce);

Will produce a nonce like:

string(128) "9e23987cf0da2f907d0eda3779bd5d4539a40d7904338c8
f198ec4a37f62a415444653e6a443aeb4f271c1f892d8b6fe0d2246fbfe7
78e5359c6b9626b6b71c2"

Forming a Valid OAuth 1.0 Request

We’ve dissected the components of an OAuth 1.0 request and should have a little bit more simplified view of how these requests are made. By taking the individual components apart, what once seemed really complex now seems a bit more realistic to grasp. How do we tie this all together? The following example is going to be an implementation of a class building an OAuth 1.0 request. For clarity’s sake, I’m going to comment the code in a way which explains what I’m doing. This example is going to be a call to a fake API with made-up tokens. Without further delay, let’s look at our classes.

Listing 3.3 shows a basic class for holding our consumer information. This will hold the token and secret generated when we register our application with an external service.

Listing 3.3

<?php
/**
 * Class to hold our Consumer information
 */
class OAuthConsumer
{
   /**
    * Consumer token
    * @var string $token
    */
   public $token;

   /**
    * Consumer secret
    * @var string $secret
    */
   public $secret;
}

We also need a class to store access information returned when a user grants us access.

Listing 3.4

<?php
/**
 * Class to hold our access information
 */
class OAuthAccess
{
   /**
    * Access Token
    * @var string $token
    */
   public $token;

   /**
    * Access Secret
    * @var string $secret
    */
   public $secret;
}

Next, the OAuthHeader class in Listing 3.5 does the hard work of building our Base String, Authorization header, and the signature for our request.

Listing 3.5

<?php
/**
 * Class to build our OAuth Headers
 */
class OAuthHeader
{
   /**
    * Callback value, if any
    * @var string $callback
    */
   protected $callback = '';

   /**
    * Value for the nonce
    * @var string $nonce
    */
   protected $nonce;

   /**
    * Request URL
    * @var string $request_url
    */
   protected $request_url;

   /**
    * HTTP Verb
    * @var string $http_verb
    */
   protected $http_verb;

   /**
    * Consumer Object
    * @var OAuthConsumer $consumer
    */
   protected $consumer;

   /**
    * Access Object
    * @var OAuthAccess $access
    */
   protected $access;

   /**
    * Constructor for OAuthHeader
    * @param OAuthConsumer $consumer
    * @param OAuthAccess $access
    */
   public function __construct(OAuthConsumer $consumer,
                               OAuthAccess $access) {
      $this->consumer = $consumer;
      $this->access = $access;
   }

   /**
    * Accessor method to set the nonce
    * @param string $nonce
    */
   public function setNonce($nonce) {
      $this->nonce = $nonce;
   }

   /**
    * Accessor method to get the nonce
    * @return string
    */
   public function getNonce() {
      return $this->nonce;
   }

   /**
    * Accessor method to set the verb
    * @param string $verb
    */
   public function setHTTPVerb($verb) {
      $this->http_verb = $verb;
   }

   /**
    * Accessor method to get the verb
    * @return string
    */
   public function getVerb() {
      return $this->http_verb;
   }

   /**
    * Accessor method to set request url
    * @param string $request_url
    */
   public function setRequestURL($request_url) {
      $this->request_url = $request_url;
   }

   /**
    * Accessor method to get request url
    * @return string
    */
   public function getRequestURL() {
      return $this->request_url;
   }

   /**
    * Accessor method to set the callback
    * @param string $callback
    */
   public function setCallback($callback) {
      $this->callback = $callback;
   }

   /**
    * Accessor method to get the callback
    * @return string
    */
   public function getCallback() {
      return $this->callback;
   }

   /**
    * Method to organize the values that will make up
    * the authorize header
    * @return array
    */
   protected function setHeaderInfo() {
      $authorize_params = array(
         'oauth_nonce' => $this->getNonce(),
         'oauth_callback' => $this->getCallback(),
         'oauth_signature_method' => 'HMAC-SHA1',
         'oauth_timestamp' => time(),
         'oauth_consumer_key' => $this->consumer->token,
         'oauth_token' => $this->access->token,
         'oauth_version' => '1.0'
      );

      if ($this->callback == '') {
         unset($authorize_params['oauth_callback']);
      }
      return $authorize_params;
   }

   /**
    * Method to buid the base string for the signature
    * @param array $authorize_params
    * @return string
    */
   protected function buildBaseString($params) {
      $temp_array = array();
      ksort($params);
      foreach ($params as $key => $value) {
         $temp_array[] = $key . '=' . rawurlencode($value);
      }

      return $this->http_verb . '&'
      . rawurlencode($this->request_url) . '&'
      . rawurlencode(implode('&', $temp_array));
   }

   /**
    * Method to build the composite key for the signature
    * @return string
    */
   protected function buildCompositeKey() {
      return rawurlencode($this->consumer->secret) . '&'
      . rawurlencode($this->access->secret);
   }

   /**
    * Method to construct the authorization header
    * @param array $params
    * @return string
    */
   protected function buildAuthHeader($params) {
      $header_prefix = 'Authorization: OAuth ';
      $values = array();
      foreach ($params as $key => $value) {
         $values[] = $key . '=' . rawurlencode($value);
      }
      $header_contents = implode(',', $values);
      return $header_prefix . $header_contents;
   }

   /**
    * Method to build the signature
    * @param string $base_string
    * @param string $composite_key
    * @return string
    */
   protected function buildSignature($base_string,
                                     $composite_key) {
      return base64_encode(hash_hmac('sha1',
         $base_string,
         $composite_key,
         true
      ));
   }

   /**
    * Method to return the entire OAuth Request header
    * ready to use
    * @return string
    */
   public function getAuthorizationHeader()    {
      $params = $this->setHeaderInfo();
      $base_string = $this->buildBaseString($params);
      $composite_key = $this->buildCompositeKey();
      $sig = $this->buildSignature(
         $base_string, $composite_key
      );
      $params['oauth_signature'] = $sig;
      return $this->buildAuthHeader($params);
   }
}

So there we’ve knocked a pretty straight-forward implementation which will generate the full authorization header for us. Is this perfect? Probably not, but as you can see the intent was to demystify the process of making an OAuth request yourself. As I stated earlier on, it’s always a great idea to use something tried and true. I mean, if it works correctly, there’s no sense in reinventing it, right?

This chapter explained the details of what’s actually happening when an OAuth request is made. If for some reason the need exists to recreate an OAuth request class, you now understand how this process flows. This wouldn’t be complete without an example of how to execute this code, so let’s take a look at Listing 3.6 to see how to execute this and what the resulting output looks like.

Listing 3.6

<?php
include_once __DIR__ . '/listing.3.3.php';

$consumer = new OAuthConsumer();
$consumer->token = 'ab234efdce1294856';
$consumer->secret = 'b77462342fdedfeaefe23423434310098';

$access = new OAuthAccess();
$access->token = '1efe342faade88421';
$access->secret = 'ccfedb764234094234212defe';

$headers = new OAuthHeader($consumer, $access);
/**
 * There would generally be a method that generates this
 * for you or building the headers would generate a new
 * nonce, doing it this for simplicity.
 */
$headers->setNonce('bfefacdede123213');
$headers->setHTTPVerb('GET');
$headers->setRequestURL(
   'https://api.example.com/v1/user/bcdef12345'
);
$header = $headers->getAuthorizationHeader();
print $header;

You can see this listing provides a relatively straight-forward interface for using this class. What happens when you run it? You should get output similar to the following (as a single string):

Authorization: OAuth oauth_nonce=bfefacdede123213,
oauth_signature_method=HMAC-SHA1,oauth_timestamp=1389156921,
oauth_consumer_key=ab234efdce1294856,
oauth_token=1efe342faade88421,oauth_version=1.0,
oauth_signature=3Ey74KvTkPjyVqodd3GtLX%2BlHPs%3D

You see a full OAuth Authorization header ready for you to use!


  1. https://github.com/vlucas/phpdotenv

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.93.207