Inconsistent handling of `$json.body`?

Describe the problem/error/question

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.

Share the output returned by the last node

[
{
“timestamp”: “1745831452”,
“plaintext”: “v1:1745831452:[object Object]”
}
]

Information on your n8n setup

  • n8n version: 1.76.4.
  • Database (default: SQLite): None
  • n8n EXECUTIONS_PROCESS setting (default: own, main): No idea
  • Running n8n via (Docker, npm, n8n cloud, desktop app): n8n cloud
  • Operating system: Windows 10

Hi,

What about JSON.stringify?

Reg
J.

JSON.stringify($json.body)

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.

Please see my reply to @jcuypers

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.

Isn’t there a raw body as option? I have seen it

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.

This problem has never been resolved. Replying to that effect as prompted by the topic being closed.

I can’t give you the solution. But it feels wrong that you try to turn an object to string in order to check a signature.

Edit: can you point to the documentation?

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.