MOST RECENT POST

AWS Product Advertising API Requires a Signed Request

Technorati Technorati Tags:

RSS Subscription
Posted In:
Aug 21st, 2010 @ 10:29 am PDT
(0) Comments

As of August 15th 2009, Amazon Web Services now require an RFC 2104–compliant HMAC signature to authenticate REST requests when using their newly named Product Advertising API. In addition, SHA256 is specified as the required hashing algorithm. Let's see how to create the required signature using PHP.

Structure of the String to Sign

Amazon requires a specific string for generating an RFC 2104-compliant HMAC signature for each call against the API. For the most part, the string is basically the usual URL for making REST calls, with some URL encoding and HTTP–like headers prepended. If you need to refresh your memory on the required structure of a REST call against AWS' Product Advertising API, you can check out my previous post, Amazon Web Services with PHP and SimpleXML.

Below is an example of the string to be signed for an ItemLookup operation:

GET <--- this one, and the next two line breaks are part of the string
ecs.amazonaws.com
/onca/xml
AWSAccessKeyId={YOUR ACCESS KEY ID}&IdType=ASIN&ItemId=1933988355&Operation=ItemLookup&ResponseGroup=Medium%2COffers&Service=AWSECommerceService&Timestamp=2009-12-30T03%3A23%3A23Z

Aspects to note:

  • Be sure to use your Access Key ID
  • The line breaks for the HTTP–like headers at the beginning are part of the string
  • The "com" in ecs.amazonaws.com may be replaced with a region identifier
  • Commas (,) and colons (:) have been highlighted to show they're properly encoded
  • Parameter/value pairs are sorted by byte order, i.e. capital–letters–first alphabetical order
  • A timestamp is required

Using PHP to Encode the String and Create a Signature

I will only describe the PHP library functions needed to create the signature out of the above string, since Ulrich Mierendorff has created an excellent PHP function for signing AWS requests given any set of parameters. His function can easily be adapted to suit your specific needs, as I have done.

As indicated above, parameters and their values need to be encoded. To this end, PHP provides the rawurlencode() function. However, the function encodes the given string according to RFC 1738 (a mostly obsolete specification). I have tested the RFC 3986 (the current generic URI syntax specification) reserved character set on rawurlencode(), and the only deviation involves the tilde (~) character. As the tilde character is part of the RFC 3986 reserved character set, it does not need to be percent-encoded. No problem, just use PHP's str_replace() function in conjunction with rawurlencode(), as shown below.

<?php
	// rawurlencode() percent-encodes ~ as %7E
	$RFC3986_encoded_string = str_replace('%7E','~',rawurlencode($some_string));
?>

There, now we have an RFC 3986 encoded string. The above functionality is useful for creating the encoded parts of the string to sign (note that not all reserved characters are encoded, e.g. equals (=) and ampersand (&) ).

Finally, we will need to produce the HMAC signature out of the string using the SHA256 algorithm. The hash_hmac() function plays the primary role, and thus PHP 5 >= 5.1.2 is required. As specified by an AWS Request Authentication web document, "the computed HMAC value should be base64 encoded", and thus the need for PHP's base64_encode() function to work in tandem with hash_hmac(). A sample of creating the signature out of the string follows:

<?php
	$signature = base64_encode(hash_hmac('sha256',$string_to_sign,{YOUR SECRET ACCESS KEY},true));
	// encode any plus (+), equal (=), or other reserved characters in $signature
	$signature = str_replace('%7E','~',rawurlencode($signature));
?>

Be sure to include your Secret Access Key provided by Amazon as the key used by hash_hmac(), and to set the last parameter to TRUE in order to return raw binary data for encoding rather than hex digits.

The Properly Formatted Signed Request

Now that the signature has been created out of the required string and your Amazon Associates Secret Access Key, all that is left is using the signature in your REST call. This is as easy as adding the URL encoded signature to your request, and the result is a valid, signed request.

Below is an example of a properly formatted signed request:

http://ecs.amazonaws.com/onca/xml?AWSAccessKeyId={YOUR ACCESS KEY ID}&IdType=ASIN&ItemId=1933988355&Operation=ItemLookup&ResponseGroup=Medium%2COffers&Service=AWSECommerceService&Timestamp=2009-12-30T22%3A44%3A37Z&Signature=HaUgW7OJl4EVNxq8%2F0of%2BnigC%2B5b8lsSUUHXkz3nSrc%3D

Aspects to note:

  • Parameter/value byte order is no longer important, this is just a basic REST request
  • All parameters and values using reserved characters are properly encoded, including the signature value
  • Required parameter/value pairs for a signed request are AWSAccessKeyId, Timestamp and Signature
  • Any other parameter/value pairs are dependent upon what type of request you are making

Summary

The process of creating a signature for AWS signed requests, is essentially the same as creating the REST request itself.

  1. Build the REST request for the type of call you want to make.
  2. Remove everything up to the first ampersand (&), i.e. the host and URI (http://ecs.amazonaws.com/onca/xml).
  3. URL encode any reserved characters in the parameters and values.
  4. Put parameter/value pairs in byte order.
  5. Prepend the HTTP–like headers including line breaks.
  6. Calculate your signature using the resulting string and URL encode the signature.
  7. Append the calculated signature to the REST request built in step 1.

Here are some resources that are sure to be of use.

AWS Signed Request FunctionProduct Advertising APIAWS Request Authentication

Again, I highly recommend Ulrich Mierendorff's AWS signed request function (linked to above) as it provides generality that can easily be adapted to your specific needs. What I have done here is try to clarify some aspects of the signing process that may not be obvious at first inspection. Good luck!

Share this Post

There are 0 comments for this post.

Add a comment to this post!

(Thanks!)

HTML Allowed (but not necessary): <p>, <a href=' '>*, <em>, <pre>, <code> & <blockquote>.  *rel='nofollow' is set for all <a> tags.