Access raw request body

I’m trying to add an outgoing webhook for Microsoft Teams to create a simple Bot using n8n.

To verify a webhook request was actually sent by Microsoft servers, it includes an HMAC signature of the request body in the Authorization header. It should be easy to verify this signature using the Crypto module, except the hashes won’t check out:
It seems like I’ll need to encrypt the raw request body, as received by Node.js.

I tried enabling the Raw Body option and using {{ $node["Webhook"].binary }} in my Crypto node, but that only yields the following error:

TypeError [ERR_INVALID_ARG_TYPE]: The "data" argument must be of type string or an instance of Buffer, TypedArray, or DataView. Received an instance of Object
    at Hmac.update (internal/crypto/hash.js:84:11)
    at Object.execute (/usr/local/lib/node_modules/n8n/node_modules/n8n-nodes-base/dist/nodes/Crypto.node.js:364:66)
    at Workflow.runNode (/usr/local/lib/node_modules/n8n/node_modules/n8n-workflow/dist/src/Workflow.js:508:37)
    at /usr/local/lib/node_modules/n8n/node_modules/n8n-core/dist/src/WorkflowExecute.js:442:62
    at processTicksAndRejections (internal/process/task_queues.js:93:5)

Full crypto node for reference:

{
  "parameters": {
    "action": "hmac",
    "type": "SHA256",
    "value": "={{$node[\"Webhook\"].binary}}",
    "dataPropertyName": "signature",
    "secret": "redacted",
    "encoding": "base64"
  },
  "name": "Calculate Signature",
  "type": "n8n-nodes-base.crypto",
  "typeVersion": 1,
  "position": [
    850,
    450
  ]
},

Hey @Radiergummi,

Did you try converting the binary data to JSON using the Read Binary node? This might solve your issue :slight_smile:

Hi @harshil1712,
I didn’t know that was necessary, but I’ll try! Just wondering which node you mean - I only see “Read binary file” which requires a file path, and “Move binary data”, which I don’t understand what it does… Appreciate your help! :slight_smile:

Hey @Radiergummi,

My bad, it’s the Move Binary Data node. IN the node, you can select the Binary to JSON mode to convert the binary to a json object. You can then reference this in your next node

Hey @harshil1712,

thanks. Added the node as required, and I can see the new property containing the JSON string, but the signatures still won’t match. I have a simple node sample from Microsoft that proves signature calculation works in the following case:

const crypto = require('crypto');
const sharedSecret = "base64-encoded-secret-here"; // e.g. "+ZaRRMC8+mpnfGaGsBOmkIFt98bttL5YQRq3p2tXgcE="
const bufSecret = Buffer(sharedSecret, "base64");

var http = require('http');

http.createServer(function(request, response) { 
	var payload = '';
	request.on('data', function (data) {
		payload += data;
	});
	
	request.on('end', function() {
		var auth = this.headers['authorization'];
		var msgBuf = Buffer.from(payload, 'utf8');
		var msgHash = "HMAC " + crypto.createHmac('sha256', bufSecret).update(msgBuf).digest("base64");
		console.log("Computed HMAC: " + msgHash);
		console.log("Received HMAC: " + auth);
// ...

That is pretty much the same thing the crypto module does, but the node sample calculates a correct signature, Crypto does not :confused:
Got any idea?

Hey @Radiergummi,

You can use the simal node in the Function node. You need to make sure that crypto is exported and accessible in the node. If you’re using the n8n cloud, you don’t need to worry about exporting it. If you’re not using n8n cloud, you can export the crypto following the instructions mentioned here: [HELP] Not been able to import external modules - #8 by jan

Do you have sample data that I can use to test the Crypto node?

Hi @harshil1712,
I just figured it out… key is the secret decoding:

const bufSecret = Buffer(sharedSecret, "base64");

This creates a buffer from the base64-encoded binary secret. It has to be passed as the binary data, otherwise decoding won’t work. So to make it work, I used the following function (in cases somone else ends up here):

for (let item of items) {
  item.json.secret = Buffer.from(item.json.rawSecret, 'base64');
}

return items;

Maybe having a trigger node for Teams’ incoming webhooks that handled all of this would be desirable?

Anyway, thanks a lot :slight_smile:

Aah, that’s perfect!

I just found a similar feature request. Can you share your use case here and upvote it?

(If it’s different, please feel free to create a new Feature Request :slight_smile: )