title: How to calculate the amazon signature for HTTP call
body: <p>I want to integrate the new service from Amazon Elastic Transcoder. Since my application is running on python 2.4 can't use boto.</p>
  
  <p>So I am writing direct http call. The problem I have is that it tells me this when I do post requests, but works for get request:</p>
  
  <blockquote>
    <p>The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.</p>
  </blockquote>
  
  <p>Here is the code:</p>
  
  <pre><code>import time
  import hmac
  import hashlib
  import urlparse
  import requests
  import json
  
  proxy = { 
                "http"  : "http://10.254.252.100:3128", 
                "https" : "http://10.254.252.100:3128", 
              }
  
  
  
  class AWSSignerV4(object):
      '''
      AWS V4 signature class.
      '''
  
      def __init__(self, access_key, key, http_verb, uri, headers, payload='', service=None, region=None):
          '''
          Instantiates a AWS V4 request signer (HMAC-256).
  
          :param access_key: AWS access key.
          :param key: AWS access secret key.
          :param http_verb: Request HTTP verb (e.g., GET or POST)
          :param uri: Request URL (http://&lt;aws-service&gt;.&lt;aws-region&gt;.amazonaws.com/[something]
          :param headers: dict with the headers used on the request. This dictionary will be updated with the authentication headers.
          :param payload: Optional payload for PUT or POST requests.
          :param service: Optional service name. By default it will be derived from the uri parameter.
          :param region: Optional AWS datacentre region. By default it will be derived from the uri parameter.
          '''
          self._key = key
          self._headers = headers
          self._http_verb = http_verb
          self._access_key = access_key
          self._payload_hash = hashlib.sha256(payload).hexdigest().lower()
  
          parsed_url = urlparse.urlparse(uri)
          expanded_netloc = parsed_url.netloc.split('.')
  
          if service is None:
              service = expanded_netloc[0]
  
          if region is None:
              region = expanded_netloc[1]
  
          self._service = service
          self._region = region
  
          if 'x-amz-date' not in headers:
              headers['x-amz-date'] = self.generate_request_date()
  
          self._timestamp = headers['x-amz-date']
          headers['x-amz-credential'] = self.credential_scope
  
          self._path = parsed_url.path
          self._query_string = self._canonicalise_querystring(parsed_url.query.strip())
          self._cheaders, self._signed_headers = self._canonicalise_headers(self._headers, parsed_url.netloc)
          self._headers['Authorization'] = self.authorization_header
  
      def __call__(self):
          '''
          This method (that makes an instance of this class a callable object) will return the updated header dictionary, including
          the AWS authorization headers.
          '''
          return self._headers
  
      #############################################
      # Instance properties
      @property
      def authorization_header(self):
          return 'AWS4-HMAC-SHA256 Credential={}/{}, SignedHeaders={}, Signature={}'.format(self._access_key, self.credential_scope,
                                                                                            self._signed_headers, self.request_signature)
  
      @property
      def request_signature(self):
          return hmac.new(self.signature_key, self.string_to_sign, hashlib.sha256).hexdigest()
  
      @property
      def canonical_request_hash(self):
          request = '{self._http_verb}\n{self._path}\n{self._query_string}\n{self._cheaders}\n{self._signed_headers}\n{self._payload_hash}'.format(**locals())
          return hashlib.sha256(request).hexdigest().lower()
  
      @property
      def string_to_sign(self):
          return 'AWS4-HMAC-SHA256\n{}\n{}\n{}'.format(self._timestamp, self.credential_scope, self.canonical_request_hash)
  
      @property
      def credential_scope(self):
          request_date = self._timestamp[:8]
          return '{}/{}/{}/aws4_request'.format(request_date, self._region, self._service)
  
      @property
      def signature_key(self):
          sign = lambda k, m: hmac.new(k, m.encode('utf-8'), hashlib.sha256).digest()
  
          k_date = sign(('AWS4' + self._key).encode('utf-8'), self._timestamp[:8])
          k_region = sign(k_date, self._region)
          k_service = sign(k_region, self._service)
          return sign(k_service, 'aws4_request')
  
      #########################################
      # Class methods
      @staticmethod
      def generate_request_date():
          return time.strftime('%Y%m%dT%H%M%SZ', time.gmtime())
  
      @staticmethod
      def _canonicalise_querystring(query):
          assert(query == '')  # TODO proper query string support will be added if required!
          return ''
  
      @staticmethod
      def _canonicalise_headers(headers, host):
          canonical_headers = {}
          canonical_headers_str = ''
  
          for key, value in headers.iteritems():
              canonical_headers[key.lower()] = value.strip()  # change to regexp to remove spaces not within "
  
          if 'host' not in canonical_headers:
              canonical_headers['host'] = host
  
          for key, value in sorted(canonical_headers.iteritems()):
              canonical_headers_str += '{}:{}\n'.format(key, value)
  
          return (canonical_headers_str, ';'.join(sorted(canonical_headers.keys())))
  
  
  # Sample code
  if __name__ == '__main__':
      headers = {}
  
  #    uri = 'https://elastictranscoder.us-east-1.amazonaws.com/2012-09-25/pipelines/1360339173389-562f0b'
      uri = 'https://elastictranscoder.us-east-1.amazonaws.com/2012-09-25/pipelines/'
  #    uri = 'https://elastictranscoder.us-east-1.amazonaws.com/2012-09-25/jobs/1360339319640-ef1c5b'
  #    uri = 'https://elastictranscoder.us-east-1.amazonaws.com/2012-09-25/jobs/'
      test_obj = AWSSignerV4('acess key', 'private key', 'POST', uri, headers)
  
      headers = test_obj()
      payload = {'Name': 'Testweb',
                 'InputBucket':'testjd5',
                 'OutputBucket':'testfinals',
                 'Role':'arn:aws:iam::789823056103:role/Elastic_Transcoder_Default_Role',
                 'Notifications':{'Progressing': '', 'Completed': '', 'Warning': '', 'Error': ''}
                 }
  #    payload = {'Input': {"Key":"9761.webm",
  #                  "FrameRate":"auto",
  #                  "Resolution":"auto",
  #                  "AspectRatio":"auto",
  #                  "Interlaced":"auto",
  #                  "Container":"webm"},
  #               'Output':{"Key":"test.mp4",
  #                  "ThumbnailPattern":"",
  #                  "Rotate":"0",
  #                  "PresetId":"1351620000000-100020"},
  #               'PipelineId':'1360339173389-562f0b'
  #               }
  #    headers['Content-Length']= '%s'%(value)
  #    print uri
  #    for key, value in headers.iteritems():
  #            call_header['%s'%(key)]= '%s'%(value)
  
  #    print headers
      print requests.post(uri, headers=headers, data=json.dumps(payload), proxies=proxy).text
  #    print requests.get(uri, headers=headers,  proxies=proxy).text
  </code></pre>
  
  <p>Can you please have a look and tell me what I am doing wrong?</p>