I am developing a webhook to process events from Stripe using Deno and the Stripe library. Recently, when trying to validate the webhook signature, I am receiving the following error:
Webhook Error: No signatures found matching the expected signature for payload.
details
API Keys: I have verified that the Stripe API keys are correct and are the same ones I use in my application. Webhook Configuration: The webhook is correctly set up in the Stripe dashboard, and I am receiving events as expected. Webhook Code: I am using the following code to process the webhook:
import "jsr:@supabase/functions-js/edge-runtime.d.ts";
import Stripe from 'https://esm.sh/[email protected]?target=deno';
import { config } from "https://deno.land/x/dotenv/mod.ts";
// Load environment variables from .env file
const env = config();
const stripeApiKey = env.STRIPE_API_KEY;
const stripeWebhookSecret = env.STRIPE_WEBHOOK_SIGNING_SECRET;
// Configure the Stripe client
const stripe = new Stripe(stripeApiKey as string, {
apiVersion: '2022-11-15',
httpClient: Stripe.createFetchHttpClient(),
});
// Start the Deno server
Deno.serve(async (request) => {
const webhookStripeSignatureHeader = request.headers.get('Stripe-Signature');
if (!webhookStripeSignatureHeader) {
return new Response('Missing Stripe signature', { status: 400 });
}
const webhookRawBody = await request.arrayBuffer();
const requestBody = new TextDecoder().decode(webhookRawBody);
const signature = webhookStripeSignatureHeader;
let event;
try {
// Construct the event from Stripe using the raw body and the signature header
event = stripe.webhooks.constructEvent(requestBody, signature, stripeWebhookSecret);
} catch (err) {
console.error(`Webhook Error: ${err.message}`);
return new Response(err.message, { status: 400 });
}
console.log(`🔔 Event received: ${event.id}`);
return new Response(JSON.stringify({ ok: true }), { status: 200 });
});
What could be causing the error "No signatures found matching the expected signature for payload" even with the correct API keys? Is there anything I can do to ensure that the request body is being passed correctly to the constructEvent function?
I have checked the environment variables, and they are loading correctly. I have tried debugging the application and verified that the request body is correct.
The common cause of this issue that request body is no longer in raw form, especially when a decoder or transform function is used.
I'd recommend using following function (reference) to retrieve the raw request body:
// First step is to verify the event. The .text() method must be used as the
// verification relies on the raw request body rather than the parsed JSON.
const body = await request.text();