-
Notifications
You must be signed in to change notification settings - Fork 2
Steps to Sign a API Request with HMAC
Developers must follow these steps in order to sign the request and make a successful and authenticated request.
This section shows the steps to sign a request with example credentials.
- access client_id: 03a01b35-b977-4e25-9003-538a9964386a
- API key: 457967861b296e9e4b5e006784f9219e8f6da355fdc9e28d7707b01ec58ad1d1
Note
The example was written in Python. Please refer documentation of your programming language to find the right code.
Let us take an example API request for this tutorial:
eg: http://localhost/oauth2/get_tags?productId=1&responseGroup=ItemAttributes,Offers,Images&version=11-0-01
The following is an example of getting tags request:
First of all you have to remember to attach the identifier and signature in headers, so that server can authenticate the request. Put followings key/value pair in the headers.
- Accept: application/json
- Authorization: Key <<base64urlsafe encoded identifier>>:<<urlsafe encoded signature>>
- Content-Type: application/x-www-form-urlencoded (optional for only "post" method)
- Put all the queries in params if the request method is GET and body if the request method is POST.
You must encode client_id with urlsafe base64 encoding method
base64.urlsafe_b64encode(<<byte encoded client_id>>)Note
Prepend this encoded client_id to canonical_string (later in the process) before the string is digested.
- Enter the time stamp. For this example, we'll use the UTC time 2018-06-01T13:33:02Z.
import datetime
datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')- URL encode the request's comma (,) and colon (:) characters, so that they don't get misinterpreted. For more information about converting to RFC 3986 specifications, see documentation and code samples for your programming language.
import urllib
params = {"productId":"1", "responseGroup":"ItemAttributes,Offers,Image", "version":"11-0-01", "timestamp":"2018-06-01T13:33:02Z"}
urllib.parse.urlencode(params)- Split the parameter/value pairs and delete the ampersand characters (&). The linebreaks used in the following example follow Unix convention (ASCII 0A, "line feed" character).
temp = "responseGroup=ItemAttributes%2COffers%2CImage&productId=1×tamp=2018-06-01T13%3A33%3A02Z&version=11-0-01"
listArgs = temp.split("&")['responseGroup=ItemAttributes%2COffers%2CImage', 'productId=1', 'timestamp=2018-06-01T13%3A33%3A02Z', 'version=11-0-01']
- Sort your parameter/value pairs by byte value (not alphabetically, lowercase parameters will be listed after uppercase ones).
listArgs.sort()Note
In python, sort() will sort the parameter/value pairs by byte value, lowercase parameters will be listed after uppercase ones.
['productId=1', 'responseGroup=ItemAttributes%2COffers%2CImage', 'timestamp=2018-06-01T13%3A33%3A02Z', 'version=11-0-01']
- Rejoin the sorted parameter/value list with ampersands. The result is the canonical string that we'll sign:
canonical_string = '&'.join(listArgs)productId=1&responseGroup=ItemAttributes%2COffers%2CImage×tamp=2018-06-01T13%3A33%3A02Z&version=11-0-01
- Prepend the following three lines (with line breaks) before the canonical string:
GET ==> method
localhost:8069
/oauth2/get_tags
Note
Use "\n" to concatenate these strings and append the final result to the sorted parameter/value pair canonical string
- The string to sign:
GET
localhost:8069
/oauth2/get_tags
productId=1&responseGroup=ItemAttributes%2COffers%2CImage×tamp=2018-06-01T13%3A33%3A02Z&version=11-0-01
- Calculate an RFC 2104-compliant HMAC with the provided (SHA256, SHA384, SHA512) hash algorithm using the string above with the example secret key. For more information about this step, see documentation and code samples for your programming language.
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, hmac
import base64
import urllib
canonical_string = "GET" + "\n" + "localhost:8069" + "\n" + "/oauth2/get_tags" + "\n" + urllib.parse.urlencode({'client_id':base64.urlsafe_b64encode(bytes(<< byte encoded client_id >>,'utf-8')).decode()}) + "&" + canonical_string
h = hmac.HMAC(b'457967861b296e9e4b5e006784f9219e8f6da355fdc9e28d7707b01ec58ad1d1',hashes.SHA256(), backend=default_backend())
h.update(bytes(canonical_string,'utf-8'))
digest = h.finalize()G8L06f4Jowk8J70LY55PuLxn7CxLO6bvoAFjWOvNA9s=
- URL encode the plus (+) and equal (=) characters in the signature:
signature = urllib.parse.quote_plus(base64.urlsafe_b64encode(digest).decode(encoding="utf-8"))G8L06f4Jowk8J70LY55PuLxn7CxLO6bvoAFjWOvNA9s%3D
Add the URL encoded signature to your request, and the result is a properly-formatted signed request:
- Accept: application/json
- Authorization: Key MDNhMDFiMzUtYjk3Ny00ZTI1LTkwMDMtNTM4YTk5NjQzODZh:G8L06f4Jowk8J70LY55PuLxn7CxLO6bvoAFjWOvNA9s%3D
- AWS Documentation
- adam-p - Markdown Cheatsheet
- Mastering Markdown
- Stackoverflow - Creating Anchor