Authenticated Endpoints

Authentication

Authenticated endpoints require users to sign their requests using an API key and API secret.

Below is a guide to authenticating HTTP requests in JavaScript. The example uses the List All Currencies endpoint, but you can easily adapt it to make requests to other endpoints.

Environments

const crypto = require("crypto");
const axios = require("axios");

const apiKey = ""; // Paste access Key here
const secretAccessKey = ""; // Paste secret access Key here

// Beta. A key only works in the environment it was created in.
const baseUrl = "https://api.hadron-beta.tether.to";

const method = "GET"; // Upper case
const apiPath = "/v1/issuer/currencies/all"; // The path only. Query parameters go in queryParameters, not in the path.
const queryParameters = {}; // One value per parameter, e.g. { page: 1, limit: 10 }
const body = undefined;

// Any string you never send again. Each nonce is accepted once, across all API keys.
const nonce = crypto.randomUUID();

// Function to flatten and sort object keys for signature generation
const flattenAndSort = (obj, prefix = "") => {
  const pairs = [];
  for (const key of Object.keys(obj).sort()) {
    const fullKey = prefix ? `${prefix}.${key}` : key;
    const value = obj[key];
    if (typeof value === "object" && value !== null && !Array.isArray(value)) {
      pairs.push(...flattenAndSort(value, fullKey));
    } else if (value !== null) {
      pairs.push(`${fullKey}=${value}`);
    }
  }
  return pairs;
};

// Sign the body as it is sent: the JSON round trip drops undefined fields and turns dates into strings, as the server sees them.
const data = {
  nonce,
  apiKey,
  url: apiPath,
  method,
  queryParameters,
  payload: body === undefined ? {} : JSON.parse(JSON.stringify(body)),
};

// Generate signature
const signaturePayload = flattenAndSort(data).join("&");
const signature = crypto
  .createHmac("sha256", secretAccessKey)
  .update(signaturePayload)
  .digest("hex");

axios({
  method,
  url: `${baseUrl}${apiPath}`,
  params: queryParameters,
  headers: {
    ...(body === undefined ? {} : { "Content-Type": "application/json" }),
    "x-api-key": apiKey,
    "x-hadron-signature": signature,
    "x-nonce": nonce,
  },
  data: body === undefined ? undefined : JSON.stringify(body),
})
  .then((res) => console.log(res.data))
  .catch((err) =>
    console.error("Request Error:", err.response?.status, err.response?.data ?? err.message)
  );

// Errors from the authentication check:
// 403 {"message":"Forbidden"}         The API key is not valid on this host (for example a beta key
//                                     on production) or is disabled.
// 500 {"error":"Invalid Api Key"}     The API key is not active.
// 500 {"error":"Invalid Signature"}   The signed text doesn't match the request: check the method,
//                                     path, query parameters and body.
// 500 {"error":"Invalid Nonce"}       The nonce was used before.
// 400 {"errorCode":"INVALID_JSON"}    Content-Type: application/json was sent without a body.

Did this page help you?