Skip to content

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 given API 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 the Message.
  • 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.