Generating a Signature
The most difficult part of building a proper request to the API is building the signature and signing it with a shared secret. In any language, a properly signed signature for the request should be generated using the following steps:
-
Combine key components of the request into a single string, using a format where each value is followed by a carriage return and line feed character. The format and table with recommended replacements is below:
{Method}\r\n{Host}\r\n{URL}\r\n{Unix Timestamp}\r\n{API Key}\r\n{Access Key}\r\n
Keyword Recommended Replacement Method HTTP Method in ALL CAPS (e.g. GET, PUT, POST, DELETE, HEAD, OPTIONS). Host Host name of server in lower case (e.g. api.ravenslingshot.com). URL Absolute URI minus query string in lower case (e.g. /fieldcomputers/460/PrescriptionMaps). Unix Timestamp Unix style timestamp of the request (number of seconds since midnight on Jan 1 1970). API Key Slingshot API Key in the case in which it was generated. Access Key Slingshot Access Key in the case in which it was generated. -
Generate an HMAC (Hash-based Message Authentication Code) using the SHA1 algorithm from the string constructed above and a 'shared secret' key.
-
The generated HMAC should then be passed along to the Slingshot API Server as the value of the X-SS-Signature request header. When the Slingshot API Server receives the request, it will do the same using the Shared Secret that matches the API Key specified in the request. If the two HMAC signatures match, the request will be considered authentic.
Examples
A function for building the signature is shown in various languages below. Test the implementation by making sure the function produces an output of EssUFos9uCpS1FFUFaPTE3Qucz0=
when provided the following strings (all encoded as UTF8):
Keyword | Replacement |
---|---|
Method | GET |
Host | host.company.com |
URL | /absolute/path |
Unix Timestamp | 1234567890 |
API Key | 071X7Hc9zdfElbB2fUqQVjAQ3BsOPa4F9l3yqekl |
Access Key | 00000000-0000-0000-0000-000000000000 |
Shared Secret | RecQ1RrXLNP/WnMqrJsj5WsuXNDmCOoCg3AV85DQ |
C#
private static string CalculateSignature(string sharedSecret,
string method,
string url,
string host,
string apiKey,
string accessKey,
string timestamp)
{
string signatureBlockTemplate = "{0}\r\n{1}\r\n{2}\r\n{3}\r\n{4}\r\n{5}\r\n";
string blockToSign = String.Format(signatureBlockTemplate,
method.ToUpperInvariant(),
host.ToLowerInvariant(),
url.ToLowerInvariant(),
timestamp,
apiKey,
accessKey);
using (HMACSHA1 hmacsha1 = new HMACSHA1())
{
Encoding encoder = new UTF8Encoding();
hmacsha1.Key = Convert.FromBase64String(sharedSecret);
byte[] hmacsig = hmacsha1.ComputeHash(encoder.GetBytes(blockToSign));
return Convert.ToBase64String(hmacsig);
}
}
Java
private String CalculateSignature(String sharedSecret,
String method,
String url, String host,
String apiKey,
String accessKey,
String timestamp) throws java.security.SignatureException
{
private String signatureBlockTemplate = "%s\r\n%s\r\n%s\r\n%s\r\n%s\r\n%s\r\n";
String blockToSign = String.format(signatureBlockTemplate,
method.toUpperCase(Locale.US),
host.toLowerCase(Locale.US),
url.toLowerCase(Locale.US),
timestamp,
apiKey,
accessKey);
String result;
try
{
// get an hmac_sha1 key from the raw key bytes
SecretKeySpec signingKey =
new SecretKeySpec(com.ss.sscompanion.utilities.Base64.decode(sharedSecret),
HMAC_SHA1_ALGORITHM);
// get an hmac_sha1 Mac instance and initialize with the signing key
Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
mac.init(signingKey);
// compute the hmac on input data bytes
byte[] rawHmac = mac.doFinal(blockToSign.getBytes());
// base64-encode the hmac
result = com.ss.sscompanion.utilites.Base64.encodeBytes(rawHmac);
}
catch (Exception e)
{
throw new SignatureException("Failed to generate HMAC : " + e.getMessage());
}
return result;
}
PHP
private function calculateSignature($sharedSecret,
$method,
$url,
$host,
$apiKey,
$accessKey,
$timestamp)
{
$signatureBlock =
sprintf("%s\r\n%s\r\n%s\r\n%s\r\n%s\r\n%s\r\n",
strtoupper($method),
$host,
strtolower($url),
$timestamp,
$apiKey,
$accessKey);
return base64_encode(hash_hmac('sha1', $signatureBlock, base64_decode($sharedSecret, true), true));
}