Authentication¶
Authentication with the APIs is done using time-based Access Tokens
generated per-request by the client application.
The Access Tokens
are sent as HTTP headers with every request to authenticate the request.
Requirements¶
Before trying to implement authentication you'll need a set of API Credentials. Every application using the API should have it's own credentials. API Credentials are made of two pieces of information:
Api Key
- A unique identifier that authorises access to data from the API.Secret
- A random string used to authenticate access to the API for a givenAPI Key
.
Caution
Secrets
must be treated as passwords and kept confidential, they should never be sent as part of a request.
Access Tokens¶
To generate an Access Token
you'll need a Timestamp
- this should be the UNIX time in seconds.
First concatenate the Secret
and Timestamp
together - this forms the Message
.
The Message
must then be passed through the HMAC-SHA256 algorithm using the Api Key
as the key. This results in hash with a length of 256 bits.
The hash must then be converted to a 64 character hexadecimal string. This is the Access Token
.
Hint
Some libraries will require the Message
and Key
to be passed into the HMAC function as byte arrays - In these scenarios use ASCII or UTF-8 encoding to convert the strings to bytes.
Example Code¶
const hmacSHA256 = require('crypto-js/hmac-sha256');
function unixTimestamp() {
return Math.floor(Date.now() / 1000);
}
function calculateAccessToken(apiKey, secret, timestamp) {
return hmacSHA256(`${secret}${timestamp}`, apiKey).toString();
}
const apiKey = 'API-0WwX9WBY6VFM1GgK40F03G80D3sV';
const secret = 'BGg47mNF0189';
const timeStamp = unixTimestamp();
const accessToken = calculateAccessToken(apiKey, secret, timeStamp);
console.log(`X-SpecCheck-ApiKey: ${apiKey}`);
console.log(`X-SpecCheck-Timestamp: ${timeStamp}`);
console.log(`X-SpecCheck-AccessToken: ${accessToken}`);
/*
Example output:
X-SpecCheck-ApiKey: API-0WwX9WBY6VFM1GgK40F03G80D3sV
X-SpecCheck-Timestamp: 1651075223
X-SpecCheck-AccessToken: 5fe5d19f852034f1d7312b190a4d0647f0857debe37bbcd4bc15486549b0df38
*/
using System;
using System.Text;
using System.Security.Cryptography;
public class Program
{
public static void Main(string[] args)
{
var apiKey = "API-C34F9XgG60Fj6Wg65IJP0YFGDGcI";
var secret = "1lg47mNK6YFb";
var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
var accessToken = ComputeAccessToken(
apiKey,
secret,
timestamp);
Console.WriteLine($"X-SpecCheck-ApiKey: {apiKey}");
Console.WriteLine($"X-SpecCheck-Timestamp: {timestamp}");
Console.WriteLine($"X-SpecCheck-AccessToken: {accessToken}");
/*
Example output:
X-SpecCheck-ApiKey: API-C34F9XgG60Fj6Wg65IJP0YFGDGcI
X-SpecCheck-Timestamp: 1651094815
X-SpecCheck-AccessToken: b6006beb626fcf89a9a69501aba300985b1d176077fe2d2296d902cac70bf561
*/
}
private string ComputeAccessToken(
string apiKey,
string secret,
int timestamp)
{
var message = $"{secret}{timestamp}";
var hash = new HMACSHA256(Encoding.ASCII.GetBytes(apiKey));
return ByteToString(hash.ComputeHash(Encoding.ASCII.GetBytes(message)));
}
private static string ByteToString(byte[] buff)
{
var builder = new StringBuilder(buff.Length);
foreach (var buffByte in buff)
{
builder.Append(buffByte.ToString("X2"));
}
return builder.ToString();
}
}
Authenticating with the API¶
Once you've used your Api Key
, Secret
and Timestamp
to generate an Access Token
you're ready to authenticate Api call.
Simply pass the the Api Key
, Timestamp
and Access Token
as headers to all HTTP requests, like so:
GET v1/regions HTTP/2
Host: api.speccheck.com
Accept: application/json
X-SpecCheck-ApiKey: API-AkRv9XgwDFFDAGgu3kB1-nZIDk0N
X-SpecCheck-Timestamp: 1651071723
X-SpecCheck-AccessToken: 741908fc2918a5f90a1f579a72030037a5c186162ecc097eed59d362054d7fcb
curl -i \
-H "X-SpecCheck-ApiKey: API-AkRv9XgwDFFDAGgu3kB1-nZIDk0N" \
-H "X-SpecCheck-Timestamp: 1651071723" \
-H "X-SpecCheck-AccessToken: 741908fc2918a5f90a1f579a72030037a5c186162ecc097eed59d362054d7fcb" \
https://api.speccheck.com/v1/regions
If the request is successfully authenticated then the API should return all available regions as a blob of JSON.
Caution
Do not send the Secret
as part of the request - this invalidates the purpose of the secret.
Example Data¶
To help with development here are 9 examples of valid Api Key
/Secret
/Timestamp
/Access Token
combinations that can be used to test code to ensure you're getting the correct results.
Api Key | Secret | Timestamp | Access Token |
---|---|---|---|
API-0nNv9WRMDVFkE1kR3m0l3YJn0Y8Z | 61k47mNEBIJP | 1651161054 | 0b4f68ae47cdba19a29c34a015d76d7451e6b65364edd7507efb5ec7449b40f0 |
API-0nNv9WRMDVFkE1kR3m0l3YJn0Y8Z | 61k47mNEBIJP | 1651161095 | 97bfcd6f46c6cb8f36f696ba09f13134d56a94c7ef0464072155919609114156 |
API-0nNv9WRMDVFkE1kR3m0l3YJn0Y8Z | 61k47mNEBIJP | 1651161132 | 8b624ccbc4b7a2d3dc165535582e54375e29d3732f86551278dfe5ff7e2cf4f0 |
API-BWZD9X08CFFS6lk03mNl7nVN6Xky | EWk47mNEBIVj | 1651161074 | 2b8c2d16f0bc6f6a821426d1a838ad46968dfd415e2a0d227842e23a44ac24f4 |
API-BWZD9X08CFFS6lk03mNl7nVN6Xky | EWk47mNEBIVj | 1651161104 | d64f390f0445151f28db2e89fb4bbc4e23f386f2300843e60413a3916031c107 |
API-BWZD9X08CFFS6lk03mNl7nVN6Xky | EWk47mNEBIVj | 1651161140 | a3d347f579a253357b9c41a6d24815ff5b812e05d0a532c2c83adfd20f01410c |
API-2XcR9VcQ3FF05Wks3mNl8ncy-nkI | C1k47mNEBIcp | 1651161084 | 3fed224edb711ef4d74defb26ef559483265ba164d30102ae9ee8c45de65e87c |
API-2XcR9VcQ3FF05Wks3mNl8ncy-nkI | C1k47mNEBIcp | 1651161123 | bccf04cbcfbccf43f12b676e4c0c880ac1a1dab3f4771fd0359fec013e2733a4 |
API-2XcR9VcQ3FF05Wks3mNl8ncy-nkI | C1k47mNEBIcp | 1651161148 | d786cdab80080c05ce9655b1adf3e6c17038f13d4bf9f98a2834fa116262f499 |
Troubleshooting¶
If you're having difficulties authenticating with the APIs here are some common issues their solutions.
If after checking this guide your still unable to connect please get in contact with us at [email protected] where we'll be happy to help!
Invalid timestamps¶
The most common issues encountered when trying to connect to the API are the timestamp not being valid at the time of request. Specifically timestamps being generated for local timezones instead of UTC.
A useful tool for checking your timestamps is unixtimestamp.com this site shows you the current timestamp and also has the facility to enter a timestamp to check. If you enter your timestamp and click the Convert button it should give you a table with information from the timestamp. The Format should be Seconds and the Relative should be less than 3 minutes.
Caution
3 minutes is meant as the relative time from when the token was generated to be used - remember to factor in the time its taken to find the timestamp and read this documentation - for example if you generated a timestamp 10 minutes ago then you're looking for a relative time between 13 minutes and 7 minutes.
If your timestamp is in any format other than Seconds you will need to divide your timestamp to change it into Seconds:
- Milliseconds - Divide by 1,000
- Microseconds - Divide by 1,000,000
- Nanoseconds - Divide by 1,000,000,000
If your time stamp relative to the current timestamp is more than 3 minutes then there may be a problem with how your calculating your UNIX time. If the time is out by a few minutes then you may need to check that your system clock is correct. If however the time gap is hours then it's more likely that local time is being used instead of UTC. For time gaps greater than a day please check how the time is being calculated.
Credential casing¶
The API Key
and Secret
are all case sensitive - the Access Token
is not.
Check:
- The casing of the
Secret
in theMessage
. - The casing of the
API Key
when passed into the hashing algorithm. - The casing of the
API Key
when passed in the HTTP headers.
Hashing algorithm¶
Please check that you're using the HMAC-SHA256 algorithm - this is not the same as SHA256.
There should be an implementation of the algorithm available in most programming languages.
Available in the crypto-js package on npm
Available in the System.Security.Cryptography
namespace.
Encoding¶
Another problem which can occur and be very difficult to spot is incorrect encoding around the hashing algorithm.
All hashing algorithms work at the byte level so at some point the strings that make up the Message
and Key
will be
encoded into a byte array. To generate a valid Access Token
these strings must be encoded using either UTF-8 or ASCII -
both encodings use the same 1-byte character codes for all the characters required by the Access Token
algorithm.
Some frameworks, such as crypto-js, will implicitly manage the encoding for you. Usually these will use UTF-8 for encoding - but if you are having issues then it may be worth checking, or changing your code to manage the encoding yourself.