Signing your Request
➡️ See also the Token Authentication 🔗.
This document will introduce you to the authentication process in order to make requests to By.Me web services.
First, you will see what is expected in your request headers and then you will see how to produce a “BM1 signature” to sign your request. Each step will be illustrated with examples as explained just below.
📌 To make sure that you understand each step of the signature process, we will follow two request examples – Request A and Request B – with the result expected for each step. For both examples we will have those shared data:
- The date and time will be August 7th 2019 at 13h37m00s GMT
- The api key will be : “BM1_ACCESS_KEY1”
- The secret key will be : “BM1_SECRET_KEY1”
Request A
Generate a Token for your Legal Entity 🔗.
Method: POST URL: https://platform.by.me/api/3/tokens to Host: "platform.by.me" to Services: "/api/3/tokens" Body (parameters.json):
{
"permission":"RW",
"tokenDuration":"100000"
}
Request B
Retrieve a project shopping list
Method: GET URL: (⚠ lowercase/uppercase) https://platform.by.me/api/3/project/shoppingList?userID=”1234”&productID=36415 to Host: "platform.by.me" to Services: "/api/3/project/shoppingList" to Query (parameters.json):
{
"userID":"1234",
"productID":"36415"
}
Request Headers for Authentication Process
You need to add the correct content-type to your headers with the following headers. Unless, we will not be able to receive your data.
For example:
content-type : “application/json”
Authentication by API Key
Request.headers
{
"apikey": "THE_API_KEY",
"signature": "THE_SIGNATURE",
"timestamp": "THE_TIMESTAMP",
"content-type": "application/json"
}
Authentication by Token
Request.headers
{
"token": "THE_TOKEN",
"timestamp": "THE_TIMESTAMP",
"content-type": "application/json"
}
Timestamp Format
Format ISO-8601 without “:” and “-“ i.e. YYYYMMDD’T’HHMMSS’Z’
Note that the “Z” in this format basically means that the time is given in GMT (also known as Zulu Time).
❗ Please make sure to create your timestamp based on a time in GMT.
In our examples, August 19th 2019 at 13h37m00s (GMT) becomes:
"20190807T133700Z"
Create the Signature with the API Key and the Request
The signature uses the API Key and the request.
📌 We are using these hash algorithms: SHA-256, HMAC-SHA256 base 64. In this document, HMAC will mean HMAC-SHA256 base 64. In this document, HexEncode will represent a function that returns the base-16 encoding of the digest in lowercase characters. Regarding URI encoding, spaces are expected to be encoded with “%20” and NOT “+”.
You will need to create different strings to get the final “String-to-sign”, to hash with your secret key that will also be modified during this process.
Step 1 – Create a Canonical Request
A canonical request is made of the following string parts.
Request Method
The method is the "HTTP verb"in the request. Either "GET", "PUT", "POST" and "DELETE".
Canonical URI
URI-encode the request services, i.e. everything from "/api/api_version/" to the specified services. For example:
"/api/1/project"
If there are no services (but, this should not happen), use this string: "/"
Canonical Query String
Step | Description |
---|---|
1 | Sort the query list (in a GET request, after the “?” in the URL) by ascending ASCII code of the key (i.e. alphabetically first uppercase then lowercase). |
2 | In case of objects: Sort the sub keys recursively by ascending ASCII code order. Sub-keys should be surrounded by brackets, and URL-encoded (see next step). |
3 | URI-encode each key and each value. Please remember that spaces are expected to be encoded with “%20” and NOT “+”. |
4 | Make a one-line string with:Canonical query string = key1+"="+value1+"&"+key2+"="+value2. Key/value pairs are separated by "&". If there is no value for a key, live an empty string. For example: key1 + "=" + "" + "&" +... |
5 | If there is no query, leave an empty string by using "", like in this example:Canonical query string= "" |
Canonical Headers
The canonical headers are the combination of the following parts:
"apikey:" + YOUR_APIKEY + "\n"
+ "host:" + THE_HOST + "\n"
+ "timestamp:" + THE_TIMESTAMP
The host is the request.hostname, that is to say the URL without "http://", the services and the port. In our examples:
Canonical headers=
apikey:BM1_ACCESS_KEY1
host:platform.by.me
timestamp:20190807T133700Z
Signed Headers
❗ Copy and paste the following string:
"apikey;host;timestamp"
Hashed Request Payload
Step | Description |
---|---|
1 | Hash with SHA-256 the request payload i.e. the http request body buffer. If there is no payload like for a GET request, hash an empty buffer. |
2 | Then hexEncode the result. |
Examples
Request A
Request payload =
{
"permission": "RW”",
"tokenDuration": "100000"
}
http request body buffer = <Buffer 7b 0a 09 22 70 65 72 6d 69 73 73 69 6f 6e 22 3a 20 22 52 57 22 2c 0a 09 22 74 6f 6b 65 6e 44 75 72 61 74 69 6f 6e 22 3a 22 31 30 30 30 30 30 22 0a 7d>
Hashed Request payload hexEncoded = c5884c11264fd47c5211f00516465b18e4e46c18d09422821732ed667f1fa046
Request B
Request payload = ""
http request body buffer = null
Hashed Request payload hexEncoded = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
Finally, the canonical request is made by concatenation of each string in the same order separated by "\n"
and ending it with a "\n"
, like in this sample:
Canonical Request =
Request Method + "\n"
+ Canonical URI + "\n"
+ Canonical query string +"\n"
+ Canonical headers + "\n"
+ Signed headers + "\n"
+ Hashed request payload + "\n"
Thus, you should get:
For Request A
Canonical Request =
POST
/api/3/tokens
apikey:BM1_ACCESS_KEY1
host:3DExperience.by.me
timestamp:20190807T133700Z
apikey;host;timestamp
c5884c11264fd47c5211f00516465b18e4e46c18d09422821732ed667f1fa046
For Request B
Canonical Request =
GET
/api/3/project/shoppingList
projectID=36415&userID=%221234%22
apikey:BM1_ACCESS_KEY1
host:3DExperience.by.me
timestamp:20190807T133700Z
apikey;host;timestamp
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Step 2 – Create the String to Sign
To create the String-to-sign, you will need the following string parts.
Part | Description |
---|---|
The algorithm | The string "BM1-HMAC-SHA256" |
Date and time | The timestamp. |
Date and services + "bm1_request" | The date (before the ‘T’ in the timestamp) + the services (ex: “/api/3/project”) + “/bm1_request”. With our examples: Request A: Date and services + “bm1_request” = “20190807/api/3/tokens/bm1_request” Request B: Date and services + “bm1_request” = “20190807/api/3/project/shoppingList/bm1_request” |
The canonical request hashed | Hash the canonical request with SHA-256. Then, hexEncode the result. With our examples: Request A: Hashed canonical request hexEncoded = e2556cbc86a06803932ed86dc08a72d397ef767fbacbe5b8b9a7fda80e2c0b0b Request B: Hashed canonical request hexEncoded = ef0f5e343dd61f9c80dc3ad7c08a5a4833c1456487d32b749efec624fcbe555b |
Finally, the String-to-sign is made by concatenation of each string in the same order separated by "\n", in other words:
String to sign=
"BM1-HMAC-SHA256" + "\n"
+ Date and time + "\n"
+ Date and services + "bm1_request" +"\n"
+ Canonical request hashed
Expected Results for our Examples
Below are two examples of what you should get.
For Request A
String to sign =
BM1-HMAC-SHA256
20190807T133700Z
20190807/api/3/tokens/bm1_request
e2556cbc86a06803932ed86dc08a72d397ef767fbacbe5b8b9a7fda80e2c0b0b
For Request B
String to sign =
BM1-HMAC-SHA256
20190807T133700Z
20190807/api/3/project/shoppingList/bm1_request
ef0f5e343dd61f9c80dc3ad7c08a5a4833c1456487d32b749efec624fcbe555b
Step 3 – Calculate the Signature
To calculate the signature, start by deriving the Secret Key. Then, generate the signature.
Derive the Secret Key
You will have to perform two HMAC hashes, then hexEncode the result to derive the secret key.
kDate = HMAC( "BM1" + secretKey, timestamp );
derivedSecretKey = HMAC( kDate, "bm1_request" );
derivedSecretKey = hexEncode(derivedSecretKey);
Expected Result
kDate = "kT9nl6YdU8ixC7jZuA5HSCdgWvpR4I2VjdA9CdSwXdM="
derivedSecretKey before hexEncoding = "r3z04rh5eJ5xgdlQgPUc3IBWrg3WCjoySgcun+djbpQ="
derivedSecretKey = "72337a3034726835654a357867646c51675055633349425772673357436a6f79536763756e2b646a6270513d"
Generate the Signature
Use HMAC with the derived Secret Key and the String-to-sign,then HexEncode the result as follow:
Signature = HexEncode ( HMAC ( derivedSecretKey, StringToSign ) )
For Request A
Signature before hexEncoding = "A9YCBore20wvq2RmYyCUl5eS0cjuhWC/k/uHfHbBRn4="
Signature = “41395943426f7265323077767132526d597943556c35655330636a756857432f6b2f754866486242526e343d"
For Request B
Signature before hexEncoding = "l0Xd5J4pCreV2YrTvBvN9oGqXy41U/op6cmOBbeAtOM="
Signature = "6c305864354a347043726556325972547642764e396f477158793431552f6f7036636d4f42626541744f4d3d"
You can now add the signature to your request headers as defined at the beginning of this page.
Your request is now authenticated and ready to be sent.
Final Headers in Request Examples
You should get the following.
For Request A
Headers =
{
"apikey": "BM1_ACCESS_KEY1",
"signature": "41395943426f7265323077767132526d597943556c35655330636a756857432f6b2f754866486242526e343d",
"timestamp": "20190807T133700Z",
"content-type": "application/json"
}
For Request B
Headers =
{
"apikey": "BM1_ACCESS_KEY1",
"signature": "6c305864354a347043726556325972547642764e396f477158793431552f6f7036636d4f42626541744f4d3d",
"timestamp": "20190807T133700Z",
"content-type": "application/json"
}