Stripe Webhooks and AWS-S3 function call issue

I am not sure but feels like the realm is transforming the request body before passing it to the attached function. Therefore “stripe.webhooks.constructEvent” is not getting the data in the desired format.

We solved the issue by manually verifying the signature with a custom function.

/***
 * This function manually validates the stripe signature for the webhook event
 *
 * Returns: boolean => true if valid request
 *
 * stripeSignature: string => Stripe-Signature received from request header i.e. request.headers["Stripe-Signature"][0]
 * requestBody:string => request body from header i.e. request.body.text()
 */
exports = function (stripeSignature, requestBody) {
  // e.g stripeSignature = "t=2345345,v1=sdfas234sfasd, v0=akhjgfska1234234123"
  const { getUnixTime } = require("date-fns");

  //0. tolerance of 5 mins
  const TOLERANCE = 300;

  //1. get webhook endpoint secret from the values
  const STRIPE_WEBHOOK_SECRET = context.values.get("STRIPE_WEBHOOK_SECRET");
  console.log("STRIPE_WEBHOOK_SECRET: ", STRIPE_WEBHOOK_SECRET);

  // 2. split the signature using "," to get a list of signature elements
  const signatureComponents = stripeSignature.split(",");

  // 3. Create a dictionary with with prefix as key for the splitted item
  const signComponentsDict = {};
  signatureComponents.forEach((item) => {
    const [prefix, value] = item.split("=");
    if (["v1", "t"].includes(prefix)) {
      signComponentsDict[prefix] = value;
    }
  });

  // 4. crete a signed payload by concatenting "t" element and the request body
  const signedPayload = `${signComponentsDict["t"]}.${requestBody}`;

  //5. the "v1" is actual signature from stripe
  const incomingSignature = signComponentsDict["v1"];

  //6. compute your own signature using the signed payload created in step 4
  const expectedSignature = utils.crypto.hmac(
    input = signedPayload,
    secret = STRIPE_WEBHOOK_SECRET,
    hash_function = "sha256",
    output_format = "hex"
  );

  //7. Get current time in unix format and also get the time from stripeSignature
  const incomingTimestamp = signComponentsDict["t"];
  const currTimestamp = getUnixTime(new Date());
  const timestampDiff = currTimestamp - incomingTimestamp;

  //8. Comparision the signature respecting tolerance
  if (timestampDiff <= TOLERANCE) {
    if (incomingSignature === expectedSignature) {
      return true;
    }
  }

  return false;
};

3 Likes