docs: function authenticateAppApiKey(cb) {
      var sentApiKey = getAppApiKey();
  
      // Fail fast if no keys
      if (!sentApiKey || !apiKey) {
        return cb({
          code: UNAUTHORISED_HTTP_CODE,
          message: "Missing App API key(s)"
        });
      }
  
      var millicore = process.env.FH_MILLICORE;
      var millicoreProt = process.env.FH_MILLICORE_PROTOCOL || "https";
      var env = process.env.FH_ENV;
      var project_id = process.env.FH_WIDGET;
      var app_id = process.env.FH_INSTANCE;
  
      var now = new Date().getTime();
  
      //check cache
      if (authenticateAppApiKeyCache.hasOwnProperty(sentApiKey)) {
        var cache = authenticateAppApiKeyCache[sentApiKey];
        //cache not timed out return cb else auth again
        if (cache.timeout > now) {
          // Cache hit
          return cb();
        } else {
          // Cache miss - remove and continue
          delete authenticateAppApiKeyCache[sentApiKey];
        }
      }
  
      var data = {
        environment: env,
        appApiKey: apiKey,
        clientApiKey: sentApiKey
      };
  
      // Call Core and validate passed key
      var url = millicoreProt + "://" + millicore + "/box/api/projects/" + project_id + "/apps/" + app_id + "/validate_key";
      request.post({
        url: url,
        json: true,
        body: data
      }, function(err, res) {
        // Can set API_KEY_VALIDATION_TIMEOUT to expire more frequently than a day
        var expiration = parseInt(process.env.API_KEY_VALIDATION_TIMEOUT, 10) || 86400000; // A day
        var cacheLength = now + expiration; // A day
  
        // Explicitly handle 404s from Millicore here - the validate_key endpoint may not exist in this cluster
        // If we get a 404, continue
        if (res.statusCode === 404) {
          authenticateAppApiKeyCache[sentApiKey] = {
            "timeout": cacheLength
          };
          return cb();
        }
  
        if (err) {
          return cb({
            code: 501,
            message: "Error talking to Core to validate API Key - please try again"
          });
        }
  
        if (res.statusCode === 200) {
          authenticateAppApiKeyCache[sentApiKey] = {
            "timeout": cacheLength
          };
          return cb();
        } else {
          return cb({
            code: UNAUTHORISED_HTTP_CODE,
            message: "Invalid API Key"
          });
        }
      });
    }