← All posts
Comparison

Telegram Webhook secret_token vs HMAC: What Your Receiver Must Verify

Telegram Bot API’s secret_token is not an HMAC signature. Set it through setWebhook, and Telegram includes the same value in X-Telegram-Bot-Api-Secret-Token on webhook requests. Your receiver checks that value against its configured secret. A UnifyPort webhook uses a different contract: when signing is enabled, verify X-Device-Signature against HMAC-SHA256 of the timestamp and exact request-body bytes. These checks are not interchangeable.

The distinction that matters

  • Telegram’s secret header is a shared credential sent with the request, not a digest calculated from the JSON body.
  • UnifyPort’s signature binds the raw body and X-Device-Timestamp to the endpoint’s signing_secret.
  • Both receivers still need HTTPS, protected secrets, and duplicate-safe processing.
  • Select the verification contract from trusted route configuration—not from an unverified JSON provider field or whichever header happens to be present.

This article concerns request authentication, not the choice of messaging identity. If that decision is still open, start with Telegram Bot API webhook vs unified inbound webhook.

What Telegram secret_token actually verifies

The official Telegram Bot API reference documents secret_token as an optional setWebhook parameter. It accepts 1–256 characters from A-Z, a-z, 0-9, _, and -. When configured, Telegram sends the value in X-Telegram-Bot-Api-Secret-Token with every webhook request.

For a receiver that requires this protection, the rule is simple: a missing or mismatched header must not enter the trusted processing queue. An exact match proves possession of the configured value. It does not establish a separate cryptographic relationship between that value and the request body.

That distinction is important at a proxy or forwarding service. If a component can read the token, it can present the same credential with a different body. HTTPS protects the transport connection; the static header itself does not detect body changes after TLS termination. This is a trust-boundary distinction, not a reason to abandon the official Bot API.

Treat the webhook secret as a dedicated credential. Do not reuse the bot token or paste the webhook secret into a public request-capture service. Keep it out of access logs, tracing exports, and support screenshots.

Static secret header vs signed body

HMAC is a keyed message-authentication mechanism. In UnifyPort’s documented implementation, the receiver recomputes a digest over a defined string rather than comparing the request header directly with the secret.

QuestionTelegram Bot API webhookSigned UnifyPort webhook
ConfigurationsetWebhook.secret_tokenEndpoint signing_secret
Header to verifyX-Telegram-Bot-Api-Secret-TokenX-Device-Signature
Value receivedThe configured token itselfHex-encoded HMAC-SHA256 digest
Body included in this check?NoYes, the exact raw bytes
Timestamp included in this check?NoYes, X-Device-Timestamp
Receiver operationCompare the header with the configured tokenRecompute and compare the digest
Guarantees one-time processing?NoNo

For UnifyPort, the signed input is exactly:

<X-Device-Timestamp>.<raw request body>

The timestamp is RFC 3339 UTC, and the dot is literal. Reformatting JSON, changing whitespace, or parsing and serializing before verification can change the signed bytes. The secret is the HMAC key; it is not the expected signature header value.

If signing_secret is empty, UnifyPort signing is disabled and X-Device-Signature is omitted. A receiver configured to require signed deliveries should reject that request rather than silently switching authentication modes.

Keep the two ingress paths separate

A practical design is to operate distinct application routes for native Telegram updates and UnifyPort events. This is an application recommendation, not an additional provider endpoint.

  1. Bind each route to a sender and credential. Set the expected mechanism in deployment configuration before accepting traffic.
  2. Authenticate before dispatch. Telegram requests must pass the secret-header check. Signed UnifyPort requests must pass the raw-body HMAC and timestamp-freshness checks.
  3. Validate the appropriate payload. Do not send a native Telegram Update to a handler expecting UnifyPort’s message.received envelope.
  4. Store accepted work durably. Keep authentication separate from idempotency and downstream business authorization.
  5. Redact sensitive material. Record which check failed without recording the secret header or credentials.

Avoid “accept either header” middleware on a shared route. That design makes the weaker or accidentally enabled branch an alternative to the intended verification policy. In particular, a Telegram secret header must never substitute for the required HMAC on a UnifyPort route.

For implementation details of the second contract, the HMAC replay-protection guide covers freshness and retry-safe processing. A timestamp in a JSON message is not a substitute for a timestamp covered by the delivery signature.

Acceptance tests before production

The following are proposed tests, not reported test results. Run them in an isolated environment using credentials you control.

TestExpected receiver behavior
Telegram header missing or incorrectReject before trusted processing
Telegram header correct, body alteredHeader check alone cannot detect the change; payload validation and the trusted transport boundary still matter
UnifyPort body altered after signingReject because the digest no longer matches
UnifyPort signature valid but timestamp outside your configured windowReject under the freshness policy
Telegram header submitted to the UnifyPort routeReject; do not change verification modes
Authentic ordinary event delivered againAccept idempotently without repeating the business action

Choose a freshness window for your clock accuracy and delivery conditions rather than copying an unrelated provider’s value. Do not interpret successful authentication as permission to execute every command contained in a message.

Where UnifyPort fits—and where it does not

UnifyPort’s unofficial interface provides normalized events from connected messaging accounts. Its HMAC protects the UnifyPort-to-your-receiver handoff. It is not a Telegram-native signature and does not prove end-to-end authorship by a Telegram user.

If your product is already a Telegram bot, implement Telegram’s documented protection on that ingress. There is no need to change platforms just to obtain a different authentication mechanism. If you use UnifyPort for an account-level or cross-channel queue, follow its own contract and enable signing when you create the webhook endpoint.

FAQ

Should I calculate HMAC with Telegram secret_token?

Not to verify the documented Bot API secret header. Compare that header with the configured token. Do not invent a body-signature algorithm for a header that carries the token itself.

Can I compare X-Device-Signature directly with signing_secret?

No. Recompute HMAC-SHA256 over the documented timestamp-plus-raw-body input, then compare the digest with the received hex signature.

Does either mechanism prevent duplicate processing?

No. Authentication and duplicate handling are separate. Persist accepted work and make downstream actions idempotent; HMAC alone does not enforce one-time delivery.

Next step and sources

Use the webhook delivery and signature reference as the implementation contract for a UnifyPort receiver.

Sources checked on 2026-09-17:

UnifyPort API

Turn messaging integration into a stable product pipeline.

Start by sending through one API, then bring every inbound message back into your business system with standard events.