api.use(async (ctx, next) => {
if (ctx.path === '/webhook') {
const sig = ctx.request.headers['stripe-signature'];
unparsed = Symbol.for('unparsedBody')
try {
event = stripe.webhooks.constructEvent(ctx.request.body[unparsed], sig, endpointSecret);
}
catch (err) {
console.log("error", err)
}
the construct event function report this error: StripeSignatureVerificationError: No signatures found matching the expected signature for payload.
So i am sure that the endpointSecret is correct, i passed the unparsedBody as well. so i am guessing it's signature error, so i used this function to verify the signature:
function verifyWebhookSignature(signatureHeader, payload, secret) {
try {
// Step 1: Extract the timestamp and signatures
const elements = signatureHeader.split(',');
let timestamp = null;
const signatures = {};
for (const element of elements) {
const [key, value] = element.split('=');
if (key === 't') {
timestamp = parseInt(value, 10);
} else if (key.startsWith('v0')) {
signatures['v0'] = value;
}
}
// If there's no timestamp or signature, or if the timestamp is too old, return false.
console.log("timestamp: ", timestamp)
if (!timestamp || (Date.now() / 1000 - timestamp) > 300) {
return false;
}
// Step 2: Prepare the signed_payload string
const signedPayload = `${timestamp}.${payload}`;
console.log("signedPayload: ", signedPayload)
// Step 3: Determine the expected signature
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
console.log("expectedSignature: ", expectedSignature)
console.log("signatures[v0]: ", signatures['v0'])
// Step 4: Compare the signatures
if (signatures['v0']) {
console.log(100)
return crypto.timingSafeEqual(
Buffer.from(expectedSignature, 'hex'),
Buffer.from(signatures['v0'], 'hex')
);
} else {
console.log(888)
return false;
}
} catch (error) {
console.log(999)
// Handle any exceptions or errors
console.error(`Signature verification failed: ${error}`);
return false;
}
}
It turns out that this line:
return crypto.timingSafeEqual(
Buffer.from(expectedSignature, 'hex'),
Buffer.from(signatures['v0'], 'hex')
);
always return false.
I print most of the data, and if you need any extra data, plz feel free to let me know.
Anyone know why? Thank you very much!
Signature verification could be going wrong in a couple different places here, as far as I can tell.
These issues are often caused by a few situations:
const endpointSecret = 'whsec_...';