Creating Access Signature
The Product Sentiment Export uses an access signature to verify that an incoming request originated from a trusted source. The access signature is a hash-based message authentication code (HMAC) consisting of values used in the request encrypted with a shared secret.
Bazaarvoice will use the values in the request along with our version of the shared secret to create our own access signature. If ours matches the one in the request, then we can be reasonably confident the request came from a trusted source.
Signature contents
The contents of the message to be encrypted will vary based on the request. The two possible variations are demonstrated below:
Without path | passkey={PSI_PASSKEY}×tamp={TIMESTAMP} |
With path | path={PATH_VALUE}&passkey={PSI_PASSKEY}×tamp={TIMESTAMP} |
The tokens above should be replaced with the appropriate values as described below:
Name | Description |
---|---|
{PATH_VALUE} |
This is the same value communicated in the path query string parameter. Refer to the Workflow Walk-Through for more information. |
{PSI_PASSKEY} |
This is the same value communicated with the |
{TIMESTAMP} |
A Unix timestamp in milliseconds. This is the same value communicated by the ⚠ Using seconds or any increment other than milliseconds will cause your request to fail |
Pseudo-code implementation
This pseudo-code demonstrates how to create an access signature:
message = utf8_encode("{MESSAGE}")
shared_secret = utf8_encode("{SHARED_SECRET}")
hmac = hmac_sha256(shared_secret, message)
access_signature = hex(hmac)
Defer to your programming language's documentation for the exact implementation.
Verification values
Use the following values to verify your implementation:
Token | Value |
---|---|
{MESSAGE} | passkey=3412n4c4n243023nc03924nc0×tamp=1502488941011 |
{SHARED_SECRET} | c73270c70932n09n09rn0r9n7 |
Using the verification values above your implementation should output the following:
b6a597270d65be4e57de826ef10ac670c6fb195c09a0c4b488f51ab32f278ac9
Code samples
The code samples below are for educational purposes only. They are not intended to be used in a production environment and are provided "as is" without warranty of any kind.
The following code samples demonstrate how to encrypt the access signature. Defer to your programming language's documentation for the exact implementation.
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
public class Main {
public static void main(String[] args) {
long time = System.currentTimeMillis();
String passkey = "{enter your passkey}";
String sharedSecret = "{enter your sharedSecret}";
//passkey and timestamp to be passed for step 1 - Request Manifest File List. Comment this and use next line of code for Step 2 and 4.
String message = "passkey=" + passkey + "×tamp=" + time;
//passkey,timestamp and path to be passed for step 2 - Request Manifest File Location and 4 - Request UGC data file location
//String message = "passkey=" + passkey + "×tamp=" + time + "&path=" + path;
try {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(sharedSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
sha256_HMAC.init(secret_key);
String digest = bytesToHex(sha256_HMAC.doFinal(message.getBytes(StandardCharsets.UTF_8)));
System.out.println("accessSignature:- " + digest);
System.out.println("Timestamp:- " + time);
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
e.printStackTrace();
}
}
private static String bytesToHex(byte[] bytes) {
StringBuilder hexString = new StringBuilder(2 * bytes.length);
for (byte b : bytes) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
}
}
using System;
using System.Security.Cryptography;
using System.Text;
public class MainClass {
public static void Main(string[] args) {
long time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
string passkey = "{enter your passkey}";
string sharedSecret = "{enter your sharedSecret}";
//passkey and timestamp to be passed for step 1 - Request Manifest File List.Comment this and use next line of code for Step 2 and 4.
string message = "passkey=" + passkey + "×tamp=" + time;
//passkey,timestamp and path to be passed for step 2 - Request Manifest File Location and 4 - Request UGC data file location
//string message = "passkey=" + passkey + "×tamp=" + time + "&path=" + path;
try {
using (HMACSHA256 hmac = new HMACSHA256(Encoding.UTF8.GetBytes(sharedSecret))) {
byte[] digestBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(message));
string digest = BytesToHex(digestBytes);
Console.WriteLine("accessSignature:- " + digest);
Console.WriteLine("Timestamp:- " + time);
}
} catch (Exception e) {
Console.WriteLine(e.Message);
}
}
private static string BytesToHex(byte[] bytes) {
StringBuilder hexString = new StringBuilder(2 * bytes.Length);
foreach (byte b in bytes) {
hexString.AppendFormat("{0:x2}", b);
}
return hexString.ToString();
}
}
const crypto = require('crypto');
function bytesToHex(bytes) {
return bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '');
}
const time = Date.now();
const passkey = "{enter your passkey}";
const sharedSecret = "{enter your sharedSecret}";
<!-- passkey and timestamp to be passed for step 1 - Request Manifest File List.Comment this and use next line of code for Step 2 and 4. -->
const message = `passkey=${passkey}×tamp=${time}`;
<!-- passkey,timestamp and path to be passed for step 2 - Request Manifest File Location and 4 - Request UGC data file location -->
<!-- const message = `passkey=${passkey}×tamp=${time}&path=${path}`; -->
try {
const hmac = crypto.createHmac('sha256', sharedSecret);
hmac.update(message);
const digest = bytesToHex(hmac.digest());
console.log("accessSignature:- " + digest);
console.log("Timestamp:- " + time);
} catch (e) {
console.error(e);
}
import sys
import hmac
import hashlib
import time
time = int(round(time.time() * 1000))
passkey = '{enter your passkey}'
sharedSecret = "{enter your sharedSecret}"
#passkey and timestamp to be passed for step 1 - Request Manifest File List.Comment this and use next line of code for Step 2 and 4.
message = "passkey="+passkey+"×tamp="+str(time)
#passkey,timestamp and path to be passed for step 2 - Request Manifest File Location and 4 - Request UGC data file location
#message = "passkey="+passkey+"×tamp="+str(time)+"&path="+path
digest = hmac.new(sharedSecret.encode('utf-8'), message.encode('utf-8'), hashlib.sha256).hexdigest()
print("accessSignature:- "+digest)
print("Timestamp:- "+str(time))
<?php
// You may need to enable the 'openssl' extension in your php.ini file.
$time = round(microtime(true) * 1000);
$passkey = "{enter your passkey}";
$sharedSecret = "{enter your sharedSecret}";
// passkey and timestamp to be passed for step 1 - Request Manifest File List.Comment this and use next line of code for Step 2 and 4.
$message = "passkey=" . $passkey . "×tamp=" . $time;
// passkey,timestamp and path to be passed for step 2 - Request Manifest File Location and 4 - Request UGC data file location
// $message = "passkey=" . $passkey . "×tamp=" . $time . "&path=" . $path ;
try {
$digest = hash_hmac('sha256', $message, $sharedSecret);
echo "accessSignature:- " . $digest . "\n";
echo "Timestamp:- " . $time . "\n";
} catch (Exception $e) {
error_log($e->getMessage());
}
function bytesToHex($bytes) {
$hexString = '';
foreach (str_split($bytes) as $byte) {
$hex = dechex(ord($byte) & 0xff);
$hexString .= str_pad($hex, 2, '0', STR_PAD_LEFT);
}
return $hexString;
}
?>
Updated 4 months ago