title: Amazon Product Affiliate REST API Integration
body: <p>I am trying to integrate with the Amazon Product Affiliate REST API, I refuse to use the SOAP integration, and please don't bring up the Soap here, I want to use REST, I am using the latest API version, which is 08/01/2013 I followed the documentation, and somehow I get always back a 403 forbidden error, I have looked all over the place, and the only thing I saw was, ppl angry about the outdated samples on Amazon, so I am getting frustrated not getting my integration work, here are the specs that I use.</p>
  
  <p>VS 2015
  Console Application targeting .NET 4.5.2
  Amazon Api version 08/01/2013</p>
  
  <p>and here is my code base.</p>
  
  <p>I have a class called AmazonRestService 
  which has all properties needed for an ItemLookup, </p>
  
  <p>in the constructor i set some properties which is the default for every request, then i have a method called SignAmazonRequest
  which takes an AmazonRestService as an argument, and i check all fields that has a value, i fill up the string that will need to be signed, </p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="false" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-html lang-html prettyprint-override"><code> public class AmazonRestService
      {
          public string Url { get; set; }
          public string Operation { get; set; }
          public string AWSAccessKeyId { get; set; }
          public string SecretKey { get; set; }
          public string AssociateTag { get; set; }
          public string ItemId { get; set; }
          public string IdType { get; set; }
          public string[] ResponseGroup { get; set; }
          public string Timestamp { get; set; }
          public string Signature { get; set; }
          public string Version { get; set; }
  
          public AmazonRestService()
          {
              Url = "http://webservices.amazon.com/onca/xml?Service=AWSECommerceService&amp;";
              AWSAccessKeyId = "XXXXXXXXXXXXXXXXXXXXX";
              AssociateTag = "xxxx-xx";
              SecretKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
              Timestamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ");
              Version = "2013-08-01";
          }
  
          public AmazonRestService SignAmazonRequest(AmazonRestService service)
          {
              var stringToSign = "";
              stringToSign = stringToSign + "AssociateTag=" + service.AssociateTag;
              if (!string.IsNullOrEmpty(service.Operation))
              {
                  stringToSign = stringToSign + "&amp;Operation=" + service.Operation;
              }
              if (!string.IsNullOrEmpty(service.ItemId))
              {
                  stringToSign = stringToSign + "&amp;ItemId=" + service.ItemId;
              }
              if (!string.IsNullOrEmpty(service.IdType))
              {
                  stringToSign = stringToSign + "&amp;IdType=" + service.IdType;
              }
              if (service.ResponseGroup.Length &gt; 0)
              {
                  stringToSign = stringToSign + "&amp;ResponseGroup=";
  
                  var lastResponse = service.ResponseGroup.Last();
  
                  foreach (var response in service.ResponseGroup)
                  {
                      stringToSign = stringToSign + response;
                      if (response != lastResponse)
                      {
                          stringToSign = stringToSign + ",";
                      }
                  }
              }
  
              stringToSign = stringToSign + "&amp;Version=" + service.Version;
              stringToSign = stringToSign + "&amp;AWSAccessKeyId=" + service.AWSAccessKeyId + "&amp;Timestamp=" + service.Timestamp;
              stringToSign = stringToSign.Replace(",", "%2C");
              stringToSign = stringToSign.Replace(":", "%3A");
              service.Url = service.Url + stringToSign;
              stringToSign = stringToSign + "&amp;Service=AWSECommerceService";
              service.Signature = HmacSha256.SignAmazonRequest(service.SecretKey, stringToSign);           
              service.Url = service.Url + "&amp;Signature=" + service.Signature;
              return service;
  
          }
  
      }</code></pre>
  </div>
  </div>
  </p>
  
  <p>once the string is ready to be signed, i call a static mehod on a different class called HmacSha256.SignAmazonRequest
  where i pass my secretKey and the string to be signed, </p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="false" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-html lang-html prettyprint-override"><code>    public static class HmacSha256
      {
          public static string SignAmazonRequest(string secretKey, string request)
          {
              var stringToSign = PrepareSignatureEncryption(request);
              var bytesToSign = Encoding.UTF8.GetBytes(stringToSign);
              var secretKeyBytes = Encoding.UTF8.GetBytes(secretKey);
              var hmacSha256 = new HMACSHA256(secretKeyBytes);
              var hashBytes = hmacSha256.ComputeHash(bytesToSign);
  
              return Convert.ToBase64String(hashBytes).Replace("+", "%2B").Replace("=", "%3D");
          }
  
          private static string PrepareSignatureEncryption(string request)
          {           
  
              var header = "GET" + Environment.NewLine
                           + "webservices.amazon.com" + Environment.NewLine
                           + "/once/xml" + Environment.NewLine;
  
              var result = header + request;
              return result;
          }
      }</code></pre>
  </div>
  </div>
  </p>
  
  <p>inside the SignAmazonRequest method, i first prepare the string as amazon wants it to be, </p>
  
  <p>i have a private helper method called PrepareSignatureEncryption
  it takes the string to be signed as an argument, and returns a ready formatted string as amazon shows in their documentation, 
  then convert the string to bytes, 
  i convert the secret key to bytes, 
  generating an HMACSHA256 based on the secret key bytes, 
  with that i compute a hash for the string to sign, 
  i return the bytes converted to base64 string, </p>
  
  <p>now with all that, here is my code in the static void main.</p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="false" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-html lang-html prettyprint-override"><code>    class Program
      {
          static void Main(string[] args)
          {
              var restService = new AmazonRestService();
              restService.Operation = "ItemLookup";
              restService.IdType = "ASIN";
              restService.ItemId = "ASINTOLOOKUP";
              restService.ResponseGroup = new string[] { "BrowseNodes", "Images", "ItemAttributes", "Offers", "Reviews", "SalesRank" };
  
              var signedRequest = restService.SignAmazonRequest(restService);
  
              Console.WriteLine(signedRequest.Url);
              Console.ReadLine();
  
              try
              {
                  var request = WebRequest.Create(signedRequest.Url);
                  var response = request.GetResponse();
                  var doc = new XmlDocument();
                  doc.Load(response.GetResponseStream());
                  doc.Save("C:/data.xml");
  
  
              }
              catch (Exception ex)
              {
  
                  var msg = ex.Message;
              }
          }
      }</code></pre>
  </div>
  </div>
  </p>
  
  <p>i am following <a href="https://aws.amazon.com/archives/Product-Advertising-API/8967000559514506" rel="nofollow noreferrer">this documentation</a>.</p>
  
  <p>any idea where i go wrong?</p>