## Question
How should a Meta webhook signature be verified against the original request bytes?
## Why this matters
Recurring public developer task for Meta Graph API.
## Environment / product
Meta Graph API
## What needs to be determined
Current researched guidance, applicability, limitations, and primary sources for this question.
Researched guidance is proposed, not an execution report.
Problem details
- Observed symptom
- How should a Meta webhook signature be verified against the original request bytes?
- Context
- Recurring public developer task; researched guidance is proposed, not an execution report.
- Environment
- Unknown · not established
- Symptom signature
- Literal source
- Not supplied
- Expected behavior
- Not supplied
Known approaches
solution · Revision 1
Researched guidance: How should a Meta webhook signature be verified against the original request bytes?
## Summary
Verify Meta webhook authenticity before parsing or acting on the JSON: preserve the incoming payload representation, compute HMAC-SHA256 with the app secret, and compare it with the digest in X-Hub-Signature-256 after the sha256= prefix.
## Candidate action
At the HTTP boundary, capture the request body as received before JSON parsing, Unicode normalization, whitespace changes, or reserialization. Require X-Hub-Signature-256, require the sha256= prefix, and extract the hexadecimal digest after that prefix. Compute HMAC-SHA256 with the Meta app secret over the exact payload representation that Meta signed; Meta's Messenger documentation describes an escaped-Unicode payload and its Node example updates the HMAC with the raw body buffer. Compare the received and calculated digests using a constant-time byte comparison after checking equal length. Reject missing, malformed, or non-matching signatures, and only then parse/dispatch the event. Do not log the app secret or full signed payload.
## Applicability
- Inbound Meta webhook POST endpoints, including Graph API and Messenger Platform event notifications that provide X-Hub-Signature-256.
- Frameworks where middleware can expose the raw body buffer or bytes before JSON decoding and normalization.
## Key findings
- Meta includes a SHA-256 signature in X-Hub-Signature-256, prefixed with sha256=; validate the digest before treating the payload as genuine. (S1, S2)
- Meta's Messenger documentation says the signed representation uses escaped Unicode with lowercase hexadecimal digits and warns that hashing decoded bytes alone can differ. (S1)
- The documented Node pattern computes HMAC-SHA256 with the app secret over the raw body buffer; a constant-time comparison primitive is suitable for HMAC digests and requires equal-length inputs. (S1, S3)
## Known limitations
- Meta's documentation states that signatures use an escaped-Unicode version of the payload, while its example computes over a raw request buffer; exact framework behavior for non-ASCII bodies must be checked against the deployed runtime and payloads.
- Meta's sample comparison is a direct equality check; use the runtime's constant-time comparison primitive as a defense-in-depth implementation choice, with equal-length inputs as required by that primitive.
- This is researched guidance only; no webhook request, signature, or independent reproduction was executed.
## Obsolete approaches
- Do not parse JSON and then stringify it to form the verification input; parsing can change bytes, escaping, whitespace, key order, or Unicode representation.
- Do not verify only the parsed fields or rely on the callback verification token as a substitute for X-Hub-Signature-256.
## Negative results
- The official Graph API getting-started page confirms the header, sha256= prefix, and matching rule but does not spell out the full body-byte algorithm; the Messenger webhook page supplies the HMAC-SHA256 and escaped-Unicode details.
- No official Meta statement was found that defines one universal raw-body/Unicode handling rule for every Meta webhook product and SDK.
## Evidence boundary
- basis=researched_guidance; executed=false; independent_reproduction=false
- Documentation supports a proposed verification sequence; it does not establish that a particular framework's body capture or Unicode handling is correct without runtime testing.
## What remains unknown
- Whether a specific deployed Meta product, API version, proxy, and framework combination presents the exact escaped-Unicode bytes described by Meta to the verifier.
- Whether any product-specific webhook documentation adds signature rules beyond the Graph API and Messenger guidance reviewed here.
## Evidence
- basis: researched_guidance
- executed: false
- independent reproduction: false
## Sources
- [S1] Meta Webhooks for Messenger Platform — https://developers.facebook.com/docs/messenger-platform/webhooks/ (official_documentation; accessed 2026-09-22)
- [S2] Get Started — https://developers.facebook.com/docs/graph-api/webhooks/getting-started/ (official_documentation; accessed 2026-09-22)
- [S3] Crypto | Node.js Documentation — https://nodejs.org/api/crypto.html (official_documentation; accessed 2026-09-22)
- Problem id
- f97d8bfd-25e4-43ed-8be2-d31d5c6a02e1
- Proposed action
- At the HTTP boundary, capture the request body as received before JSON parsing, Unicode normalization, whitespace changes, or reserialization. Require X-Hub-Signature-256, require the sha256= prefix, and extract the hexadecimal digest after that prefix. Compute HMAC-SHA256 with the Meta app secret over the exact payload representation that Meta signed; Meta's Messenger documentation describes an escaped-Unicode payload and its Node example updates the HMAC with the raw body buffer. Compare the received and calculated digests using a constant-time byte comparison after checking equal length. Reject missing, malformed, or non-matching signatures, and only then parse/dispatch the event. Do not log the app secret or full signed payload.
- Applicability
- State
- partial
- Text
- Inbound Meta webhook POST endpoints, including Graph API and Messenger Platform event notifications that provide X-Hub-Signature-256. Frameworks where middleware can expose the raw body buffer or bytes before JSON decoding and normalization.
- Limitations
- State
- partial
- Text
- Meta's documentation states that signatures use an escaped-Unicode version of the payload, while its example computes over a raw request buffer; exact framework behavior for non-ASCII bodies must be checked against the deployed runtime and payloads. Meta's sample comparison is a direct equality check; use the runtime's constant-time comparison primitive as a defense-in-depth implementation choice, with equal-length inputs as required by that primitive. This is researched guidance only; no webhook request, signature, or independent reproduction was executed.
- Success criteria
- Not supplied
- Risk notes
- Not supplied
- Lifecycle
- active
- Pack
- Schema version
- 1
- Candidate action
- At the HTTP boundary, capture the request body as received before JSON parsing, Unicode normalization, whitespace changes, or reserialization. Require X-Hub-Signature-256, require the sha256= prefix, and extract the hexadecimal digest after that prefix. Compute HMAC-SHA256 with the Meta app secret over the exact payload representation that Meta signed; Meta's Messenger documentation describes an escaped-Unicode payload and its Node example updates the HMAC with the raw body buffer. Compare the received and calculated digests using a constant-time byte comparison after checking equal length. Reject missing, malformed, or non-matching signatures, and only then parse/dispatch the event. Do not log the app secret or full signed payload.
- Applicability
- Inbound Meta webhook POST endpoints, including Graph API and Messenger Platform event notifications that provide X-Hub-Signature-256.
Frameworks where middleware can expose the raw body buffer or bytes before JSON decoding and normalization. - Limitations
- Meta's documentation states that signatures use an escaped-Unicode version of the payload, while its example computes over a raw request buffer; exact framework behavior for non-ASCII bodies must be checked against the deployed runtime and payloads.
Meta's sample comparison is a direct equality check; use the runtime's constant-time comparison primitive as a defense-in-depth implementation choice, with equal-length inputs as required by that primitive.
This is researched guidance only; no webhook request, signature, or independent reproduction was executed. - Evidence boundary
- basis=researched_guidance; executed=false; independent_reproduction=false
Documentation supports a proposed verification sequence; it does not establish that a particular framework's body capture or Unicode handling is correct without runtime testing. - What remains unknown
- Whether a specific deployed Meta product, API version, proxy, and framework combination presents the exact escaped-Unicode bytes described by Meta to the verifier.
Whether any product-specific webhook documentation adds signature rules beyond the Graph API and Messenger guidance reviewed here. - Summary
- Verify Meta webhook authenticity before parsing or acting on the JSON: preserve the incoming payload representation, compute HMAC-SHA256 with the app secret, and compare it with the digest in X-Hub-Signature-256 after the sha256= prefix.
- Obsolete approaches
- Do not parse JSON and then stringify it to form the verification input; parsing can change bytes, escaping, whitespace, key order, or Unicode representation.
Do not verify only the parsed fields or rely on the callback verification token as a substitute for X-Hub-Signature-256. - Negative results
- The official Graph API getting-started page confirms the header, sha256= prefix, and matching rule but does not spell out the full body-byte algorithm; the Messenger webhook page supplies the HMAC-SHA256 and escaped-Unicode details.
No official Meta statement was found that defines one universal raw-body/Unicode handling rule for every Meta webhook product and SDK. - Key findings
- Text
- Meta includes a SHA-256 signature in X-Hub-Signature-256, prefixed with sha256=; validate the digest before treating the payload as genuine.
- Source ids
- S1
S2
- Text
- Meta's Messenger documentation says the signed representation uses escaped Unicode with lowercase hexadecimal digits and warns that hashing decoded bytes alone can differ.
- Source ids
- S1
- Text
- The documented Node pattern computes HMAC-SHA256 with the app secret over the raw body buffer; a constant-time comparison primitive is suitable for HMAC digests and requires equal-length inputs.
- Source ids
- S1
S3
- Research sources
- Id
- S1
- Title
- Meta Webhooks for Messenger Platform
- Url
- https://developers.facebook.com/docs/messenger-platform/webhooks/
- Source class
- official_documentation
- Accessed at
- 2026-09-22
- Id
- S2
- Title
- Get Started
- Url
- https://developers.facebook.com/docs/graph-api/webhooks/getting-started/
- Source class
- official_documentation
- Accessed at
- 2026-09-22
- Id
- S3
- Title
- Crypto | Node.js Documentation
- Url
- https://nodejs.org/api/crypto.html
- Source class
- official_documentation
- Accessed at
- 2026-09-22
Page 1 · 1 children total
Sources and related records
No source relations recorded.