ComposioHQ/composio · error · ComposioWebhookSignatureVerificationError
No valid v1 signature found in the webhook-signature header.
Error message
No valid v1 signature found in the webhook-signature header. Expected format: 'v1,base64EncodedSignature'
What it means
The 'webhook-signature' header must contain at least one signature in the versioned format 'v1,<base64HMAC>'. The parser splits entries and keeps those whose version prefix is 'v1' with a non-empty value; if none qualify, this ComposioWebhookSignatureVerificationError is thrown. This catches malformed or future-versioned signature headers before any HMAC comparison.
Source
Thrown at ts/packages/core/src/models/Triggers.ts:1270
if (webhookTimestamp.length === 0) {
throw new ComposioWebhookSignatureVerificationError(
"No webhook timestamp was provided. Please pass the value of the 'webhook-timestamp' header."
);
}
// Parse signature - may have multiple signatures prefixed with version (e.g., "v1,base64sig")
const signatures = signature.split(' ');
const v1Signatures: string[] = [];
for (const sig of signatures) {
const [version, value] = sig.split(',');
if (version === 'v1' && value) {
v1Signatures.push(value);
}
}
if (v1Signatures.length === 0) {
throw new ComposioWebhookSignatureVerificationError(
'No valid v1 signature found in the webhook-signature header. ' +
"Expected format: 'v1,base64EncodedSignature'"
);
}
// Compute expected signature: HMAC-SHA256(msgId.timestamp.payload, secret) -> base64
const toSign = `${webhookId}.${webhookTimestamp}.${payload}`;
const expectedSignature = await hmacSha256Base64(secret, toSign);
// Check if any of the provided signatures match
let isValid = false;
for (const providedSignature of v1Signatures) {
if (timingSafeEqual(providedSignature, expectedSignature)) {
isValid = true;
break;
}
}
View on GitHub (pinned to 64b1b85502)
Solutions
- Send/forward the header verbatim from Composio: 'v1,' + base64(HMAC-SHA256(msgId.timestamp.payload, secret))
- If computing signatures yourself (tests), prefix the base64 HMAC with 'v1,'
- Do not parse/reformat the header before passing it to the SDK
- Check for SDK/backend version drift if Composio now sends a different version prefix
Example fix
// before (test helper)
const sig = crypto.createHmac('sha256', secret).update(msg).digest('base64');
// after
const sig = 'v1,' + crypto.createHmac('sha256', secret).update(`${msgId}.${ts}.${payload}`).digest('base64'); Defensive patterns
Strategy: validation
Validate before calling
const sig = String(req.headers['webhook-signature'] ?? '');
const hasV1 = sig.split(' ').some(p => { const [v, val] = p.split(','); return v === 'v1' && !!val; });
if (!hasV1) return res.status(400).send('Bad signature header'); Type guard
const hasV1Signature = (sigHeader: unknown): sigHeader is string =>
typeof sigHeader === 'string' &&
sigHeader.split(' ').some(part => { const [v, val] = part.split(','); return v === 'v1' && !!val; }); Try / catch
try { verifyWebhookSignature(...); } catch (e) { if (e instanceof ComposioWebhookSignatureVerificationError) return res.status(400).end(); throw e; } Prevention
- Never hand-build the signature header; use values produced by Composio or a correct 'v1,'+base64 HMAC in tests
- Reject requests whose signature header lacks a v1 entry before invoking verification
- Pin SDK versions in tests that compute signatures
When it happens
Trigger: Passing a signature header that is raw base64 without the 'v1,' prefix, an empty string, a wrong scheme like 'sha256=...', or only unsupported version prefixes (e.g. 'v2,...').
Common situations: Copy-pasting verification code from Svix/Stripe-style schemes (sha256=), hand-crafting test signatures, or a provider version change that alters the signature header format.
Related errors
- No webhook ID was provided. Please pass the value of the 'we
- No webhook timestamp was provided. Please pass the value of
- Invalid parameters passed to set webhook subscription
- The signature provided is invalid. Please ensure you are usi
- Invalid webhook timestamp: ${webhookTimestamp}. Expected Uni
AI-assisted analysis of ComposioHQ/composio@64b1b85502 (2026-08-28).
Data as JSON: /api/errors/038c15d02fb761f4.
Report an issue: GitHub.