Closed
Description
Issue Summary
I am struggling with the EventWebhook signing procedure a while now and can't get it to work. Tried multiple options, including using the raw req body for the timestamp. The verification always fails..
Edit: I am using the verifySignature function from the eventwebhook package here.
Edit 2: Added sample data that was gathered by logging the respective constants.
Steps to Reproduce
- Setup an express server, deploy it somewhere and trigger the Webhook.
Code Snippet
import express from "express";
import cors from "cors";
import asyncHandler from "express-async-handler";
import createError from "http-errors";
// @ts-ignore
import { Ecdsa, Signature, PublicKey } from '@starkbank/ecdsa';
const app = express();
app.use(cors({ origin: true }));
app.use(
express.json({
verify: (req, res, buf) => {
// @ts-ignore
req.rawBody = buf;
},
})
);
const verifySignature = (publicKey: PublicKey, payload: any, signature: string, timestamp: string) => {
let timestampPayload = typeof payload === 'object' ? JSON.stringify(payload) : payload;
timestampPayload = timestamp + timestampPayload;
const decodedSignature = Signature.fromBase64(signature);
return Ecdsa.verify(timestampPayload, decodedSignature, publicKey);
}
app.post(
"/event",
asyncHandler(async (req, res) => {
const signature = req.get('X-Twilio-Email-Event-Webhook-Signature');
const timestamp = req.get('X-Twilio-Email-Event-Webhook-Timestamp');
const payload = req.body; // req.rawBody also does not work
if (!signature || !timestamp || !payload) {
throw createError(403, "Unauthorized Request");
}
console.log('verifying')
console.log(signature)
console.log(timestamp)
console.log(JSON.stringify(payload))
const publicKey = PublicKey.fromPem(functions.config().env.sendgrid.publicKey);
if(!verifySignature(publicKey, payload, signature, timestamp)) {
throw createError(403, "Unauthorized Request");
}
console.log('verified')
})
);
// @ts-ignore
app.use((error, req, res, _) => {
res.status(error.status || 500);
res.json({
status: error.status,
message: error.message,
});
console.error(error.message)
});
// sample data from logs above
const TIMESTAMP = "1591866114"
const PAYLOAD = [{"email":"heyanna-test@hotmail.com","event":"bounce","ip":"167.89.17.173","mc_stats":"singlesend","phase_id":"send","reason":"550 5.5.0 Requested action not taken: mailbox unavailable (S2017062302). [VE1EUR03FT058.eop-EUR03.prod.protection.outlook.com]","send_at":"1591866054","sg_event_id":"Ym91bmNlLTAtMTU2MTI0NDktQTVjTHQweTBTWXlBLXN2N3RWNUQydy0x","sg_message_id":"A5cLt0y0SYyA-sv7tV5D2w.filterdrecv-p3iad2-784dbb6bd8-cmnvf-19-5EE1F2DB-11B.1","sg_template_id":"d-bb3d0c9fd0e1494f990a9d386437c6b0","sg_template_name":"Clone: Clone: Clone: Clone: Clone: Clone: Clone: Clone: Clone: Clone: Clone 2020-06-11T08:58:41.387Z","singlesend_id":"bfba94a4-abc1-11ea-b5ff-fac9c7677002","singlesend_name":"DEV-Test 11","smtp-id":"<A5cLt0y0SYyA-sv7tV5D2w@ismtpd0087p1mdw1.sendgrid.net>","status":"5.5.0","template_hash":"030c05c8aa7b8112e5e2d6a99def801d95ccb03f0cf0388874129b4dfb1f41e9","template_id":"d-bb3d0c9fd0e1494f990a9d386437c6b0","template_version_id":"a55a3135-fdf9-41af-8c29-7b93962baab7","timestamp":1591866077,"tls":1,"type":"bounce"}]
const PUBLIC_KEY = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETg3hldXJ3S/JlTbsYXdYCDuSpQHISB5C9xPgDkqjjPAyVIVhwSTR7UhIWC7mpvXa4vmCNyAucNmHAosg3p0/eA=="
const SIGNATURE = "MEYCIQCKLxRqhAbX/XlPl35AoiOII6l5D64R21TaiX4TB8sejQIhAJc/PM1SDCkfdyx6gu9Up1GjbJyHz2m6jicfyjaKJupj"
Exception/Log
Unauthorized Request