hcengineering/platform · error
Missing signature
Error message
Missing signature
What it means
The handler responds 400 'Missing signature' when the stripe-signature header is absent. Without it constructEvent cannot verify the request, so it is rejected before verification is attempted.
Source
Thrown at services/payment/pod-payment/src/providers/stripe/webhook.ts:51
webhookSecret: string,
stripeApiKey: string,
req: Request,
res: Response
): Promise<void> {
try {
// Body is a Buffer from express.raw() middleware
const rawBody = req.body as Buffer
const sig = req.headers['stripe-signature'] as string
if (!(rawBody instanceof Buffer) || rawBody.length === 0) {
ctx.error('Invalid webhook body')
res.status(400).json({ error: 'Invalid body' })
return
}
if (sig === undefined) {
ctx.error('Missing Stripe signature header')
res.status(400).json({ error: 'Missing signature' })
return
}
// Create Stripe instance for webhook verification
const stripe = new Stripe(stripeApiKey, { apiVersion: '2025-02-24.acacia' })
// Verify webhook signature and parse event
let event: Stripe.Event
try {
event = stripe.webhooks.constructEvent(rawBody, sig, webhookSecret)
} catch (err: any) {
ctx.error('Invalid Stripe webhook signature', { err })
res.status(403).json({ error: 'Invalid signature' })
return
}
// Route to appropriate handler based on event type
switch (event.type) {View on GitHub (pinned to 63e28dc964)
Solutions
- Only let Stripe (or stripe listen / stripe CLI) call this endpoint; the signature header is added automatically by Stripe
- If testing manually, include a valid Stripe-Signature header generated via stripe CLI
- Check ingress/proxy header stripping (e.g. nginx underscores_in_headers or WAF rules)
- Verify the webhook endpoint URL registered in Stripe matches this route
Example fix
// before
curl -X POST http://host/webhooks/stripe -d '{...}'
// after
stripe listen --forward-to localhost:3000/webhooks/stripe
stripe trigger customer.subscription.created Defensive patterns
Strategy: validation
Validate before calling
const sig = req.headers['stripe-signature'] as string | undefined
if (sig === undefined) {
throw new Error('stripe-signature header required; only Stripe should call this endpoint')
} Type guard
function hasStripeSignature(headers: Record<string, unknown>): headers is Record<string, string> & { 'stripe-signature': string } {
return typeof headers['stripe-signature'] === 'string'
} Prevention
- Only call the endpoint via Stripe or stripe CLI
- Keep the route unauthenticated and signature-verified
- Verify proxies don't strip custom headers
- Check endpoint URL in Stripe dashboard matches the route
When it happens
Trigger: Caller posts directly to the endpoint (curl/health check) without a stripe-signature header; Stripe CLI forwarded to the wrong path; a proxy strips the custom header; event delivered by something other than Stripe.
Common situations: Manual smoke tests hitting the webhook URL; ingress rules or middleware that drop unknown headers; misconfigured Stripe CLI forward target.
Related errors
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/ad6afdbb041e3d37.
Report an issue: GitHub.