HMAC Signing Example in Node

Veracode Integrations Security and Troubleshooting

This Node example shows you how to enable HMAC signing within your application. The example implementation of the HMAC signing algorithm allows you to authenticate with the Veracode APIs.

Before you begin, install the crypto-js library by running:

npm install crypto-js

HmacRequestSigner.js

const url = require('url');
const CryptoJS = require("crypto-js");

// Set these two values to your Veracode API Credentials' ID and Secret Key.
// Do not check your ID and Secret Key in to source control. Store them securley.
const id = 'YOUR_VERACODE_API_KEY_ID';
const key = 'YOUR_VERACODE_API_KEY_SECRET';

// These constants are required to generate HMAC credentials, and they don't have to change.
const authorizationScheme = 'VERACODE-HMAC-SHA-256';
const requestVersion = "vcode_request_version_1";
const nonceSize = 16;
          
/**
 * This function HMACs a message with the key_hex and returns a hex representation.
 *
 * @param {string | CryptoJS.lib.WordArray} message - The message to hash.
 * @param {string | CryptoJS.lib.WordArray} key_hex - The secret key.
 *
 * @returns {string} - hex representation of HMAC'd message
 */
function computeHashHex(message, key_hex) {
    return CryptoJS.HmacSHA256(message, CryptoJS.enc.Hex.parse(key_hex)).toString(CryptoJS.enc.Hex);
}
          
/**
 * Calculate the signature (sig) value of the Authorization header.
 *
 * @param {string} key - The Veracode API Credentials Key
 * @param {string} nonceBytes - The Veracode API Credentials Secret Key
 * @param {string} dateStamp - Current date as a string in epoch time
 * @param {string} data - Data to be signed
 *
 * @returns {string} signature value
 */
function calculateDataSignature(key, nonceBytes, dateStamp, data) {
    let kNonce = computeHashHex(nonceBytes, key);
    let kDate = computeHashHex(dateStamp, kNonce);
    let kSig = computeHashHex(requestVersion, kDate);
    let kFinal = computeHashHex(data, kSig);
    return kFinal;
}
          
/**
 * Return a random 16 character length hex string. This prevents requests from being replayed.
 */
function newNonce() {
    return CryptoJS.lib.WordArray.random(nonceSize).toString().toUpperCase();
}
          
/**
 * Convert UTF8 string to hex string.
 *
 * @param {string} input UTF8 string input
 */
function toHexBinary(input) {
   return CryptoJS.enc.Hex.stringify(CryptoJS.enc.Utf8.parse(input));
}
          
/**
 * Calculate the header for authentication to the Veracode Platform.
 *
 * @param {string} httpMethod - HTTP method the request uses.
 * @param {string} requestUrl - URL which must including host, path, and query params, if present.
 */
function calculateVeracodeAuthHeader(httpMethod, requestUrl) {
    // Assume the function is called with these two values:
    // - httpMethod: "GET"
    // - requestUrl: "https://api.veracode.com/api/authn/v2/users/self"
    // And assume the Veracode credentials are as follows:
    // - id: "0123456789abcdef0123456789abcdef"
    // - key: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
    let parsedUrl = url.parse(requestUrl);
    let data = `id=${id}&host=${parsedUrl.hostname}&url=${parsedUrl.path}&method=${httpMethod}`;
    // data: id=0123456789abcdef0123456789abcdef&host=api.veracode.com&url=/api/authn/v2/users/self&method=GET
    let dateStamp = Date.now().toString();
    // dateStamp: 1613497877215
    let nonceBytes = newNonce(nonceSize);
    // nonceBytes: A677F3C1C50BAAF2F36363E40C349A74
    let dataSignature = calculateDataSignature(key, nonceBytes, dateStamp, data);
    // dataSignature: 36321405a5aaac41bf01e98673ee711bc1522284acfc30014b1e27d55d49db20
    let authorizationParam = `id=${id},ts=${dateStamp},nonce=${toHexBinary(nonceBytes)},sig=${dataSignature}`;
    // authorizationParam: id=0123456789abcdef0123456789abcdef,ts=1613497877215,nonce=4136373746334331433530424141463246333633363345343043333439413734,sig=36321405a5aaac41bf01e98673ee711bc1522284acfc30014b1e27d55d49db20
    let header = authorizationScheme + " " + authorizationParam;
    // header: VERACODE-HMAC-SHA-256 id=0123456789abcdef0123456789abcdef,ts=1613497877215,nonce=4136373746334331433530424141463246333633363345343043333439413734,sig=36321405a5aaac41bf01e98673ee711bc1522284acfc30014b1e27d55d49db20
    return header;
}
          
// One way to use this example is in Postman.
// To set the 'hmacAuthHeader' environment variable you can do the following:
postman.setEnvironmentVariable('hmacAuthHeader', calculateVeracodeAuthHeader(request['method'], request['url']));