Farooq Hanif
Farooq Hanif

Reputation: 1909

How to create signed webhook requests in nodejs?

I have 2 nodejs microservices (let call them service x and service y). In service x, I will be making POST requests to service y.

Lets say service x will POST at this HTTPs endpoint in service y: /order/orderId

I think of service x as a webhooks producer, and service y to be webhooks consumer.

I want service y to be able to ensure that the message is coming from service x, and not from any malicious source. For this to work, I want to sign requests within service x before it makes POST request to service y.

What options do I have to sign these requests? How can I sign these reqeusts in service x, and how do I validate these requests in service y? Also what signing/encryption options do I have?

Concrete code examples in nodejs will be of great help.

Upvotes: 4

Views: 2064

Answers (1)

Majed Badawi
Majed Badawi

Reputation: 28434

You can use a secret key between the two services exclusively and use it to sign the requests.

In the sender (service x):

  • Append a custom header for the HTTP POST request, x-webhook-signature, which will be a generated sha256 HMAC using the secret key:
function createHmacSignature(req) {
  return require("crypto")
    .createHmac("sha256", secretKey)
    .update(JSON.stringify(req.body))
    .digest("hex");
}

In the receiver (service y):

  • Get the signature header:
req.headers["x-webhook-signature"]
  • Using the secret key, create the HMAC again as above.
  • Compare the resulted string with the x-webhook-signature header, if they match, the request origin would be the expected one.
function compareSignatures (signature, comparison_signature) {
  const source = Buffer.from(signature);
  const comparison = Buffer.from(comparison_signature);
  return require("crypto").timingSafeEqual(source, comparison);
}

Of course, extra validations and enhancements can be done, this is the normal flow to guarantee that only service x can send the request.

Upvotes: 4

Related Questions