I need to get the raw body of an incoming webhook message to run an HMAC signature verification on it.
The verification requires the generation of a string of the form “v1::” where is a timestamp provided in the HTTP headers and is the raw message body.
When I use the expression {{ $json.body }} I get the correct message body as expected, e.g. {"foo":"bar"}.
However, when I try to form the plaintext string by concatenating it as the expression {{ "v1:" + $json.headers.timestamp + ":" + $json.body }} , the $json.body, which worked on its own in the previous expression, now returns the string “[object Object]” instead of {"foo":"bar"} and the resulting string is v1:1745831452:[object Object]
So it appears that $json.body produces a different result when used on its own in expression as {{ $json.body }} from what it produces when used in a more complex expression such as {{ "foo:" + $json.body }}.
I’ve also tried using v1:1745831452:{{ $json.body }} and this too returns “v1:1745831452:[object Object]”.
Expected output
v1:1745831452:{"foo":"bar"}
Please share your workflow
I can’t share the nodes because they contain private data and I can’t edit them because the webhook node has binary data. However, it’s easy to reproduce the issue.
This isn’t a good idea because the output of stringify is often different from the input from the HTTP message. An extra or missing space in the formatting is enough to make the hash fail. Even one bit of difference will fail it.
By the way, I did try stringify and it failed for the reasons above.
What it requires is a simple option to tell n8n not do tamper with the input at all and pass it straight through. In other words, tell n8n to get out of the way. I had some other issues with it automatically converting escape sequences as well. For most uses, this is the correct behaviour as the user wants to see unicode, slashes and backslashes in the output string. However, when you need to check a message signature there has to be a way to get at the raw input message without ANY fiddling by n8n trying to be helpful.
I already have the raw body option set, which enables access to $json.body. However, it’s NOT the raw body, it’s an interpreted body with things like unescaping escape sequences. It’s a processed body. It would be best to add a processedBody option as well, so you can get at that if you need to. But the raw body should be exactly that, and it isn’t.
There’s absolutely nothing wrong with this, regardless of your feelings about it. It’s completely standard practice in cryptography. It’s absolutely necessary in order to compute a hash correctly. You need to have the exact byte-by-byte representation without any tampering with it, or the computed hash will not match the original hash.