Skip to content

Steps to Sign a API Request with HMAC

Bishal Pun edited this page Jun 15, 2018 · 21 revisions

Example REST Requests

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.

Note

The example was written in Python. Please refer documentation of your programming language to find the right code.

Example request to sign

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:

http://localhost:8069/oauth2/get_tags?productId=1&responseGroup=ItemAttributes%2COffers%2CImage&timestamp=2018-06-01T13%3A33%3A02Z&version=11-0-01

Headers configuration

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.

Encoding client_id with base64

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.

Steps to Sign the Example Request

  1. 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')

http://localhost/oauth2/get_tags?productId=1&responseGroup=ItemAttributes,Offers,Images&version=11-0-01&timestamp=2018-06-01T13:33:02Z

  1. 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)

http://localhost/oauth2/get_tags?responseGroup=ItemAttributes%2COffers%2CImage&productId=1&timestamp=2018-06-01T13%3A33%3A02Z&version=11-0-01

  1. 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&timestamp=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']

  1. 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']

  1. 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&timestamp=2018-06-01T13%3A33%3A02Z&version=11-0-01

  1. 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

  1. The string to sign:

GET

localhost:8069

/oauth2/get_tags

productId=1&responseGroup=ItemAttributes%2COffers%2CImage&timestamp=2018-06-01T13%3A33%3A02Z&version=11-0-01

  1. 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=

  1. 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

Final Request with headers

Add the URL encoded signature to your request, and the result is a properly-formatted signed request:

The final request

http://localhost:8069/oauth2/get_tags?productId=1&responseGroup=ItemAttributes%2COffers%2CImage&timestamp=2018-06-01T13%3A33%3A02Z&version=11-0-01

With headers

  1. Accept: application/json
  2. Authorization: Key MDNhMDFiMzUtYjk3Ny00ZTI1LTkwMDMtNTM4YTk5NjQzODZh:G8L06f4Jowk8J70LY55PuLxn7CxLO6bvoAFjWOvNA9s%3D

Acknowledgments