Webhook Security
Webhook hardening path
Start with the native launch mode, then move to framework adapters when you already own the HTTP server.
Native launch mode
Use `bot.launch({ webhook })` when VibeGram should own the HTTP server lifecycle.
Adapter health checks
Mount the same adapter on webhook and health routes where your framework needs both.
Framework adapters
Express, Fastify, Hono, Koa, and native HTTP share the same security shape.
When using webhooks, VibeGram supports Telegram's secret_token verification to prevent unauthorized requests.
Setup
import express from 'express';
import { Bot } from 'vibegram';
const bot = new Bot('YOUR_BOT_TOKEN');
const WEBHOOK_SECRET = 'my-secure-random-secret';
const app = express();
app.use(express.json());
// The callback validates X-Telegram-Bot-Api-Secret-Token header
app.post('/webhook', bot.webhookCallback(WEBHOOK_SECRET));
app.listen(3000);How It Works
- When setting the webhook, include
secret_tokenin the API call - Telegram includes this token in the
X-Telegram-Bot-Api-Secret-Tokenheader webhookCallback()verifies the header matches your secret- Requests with invalid or missing tokens receive
403 Forbidden
Native Launch Mode
For a standalone deployment, bot.launch({ webhook }) can own the native HTTP server and register the webhook for you:
await bot.launch({
webhook: {
url: process.env.WEBHOOK_URL!,
port: Number(process.env.PORT ?? 3000),
path: '/webhook',
secretToken: process.env.WEBHOOK_SECRET,
healthPath: '/healthz',
},
});healthPath returns 200 OK for uptime checks without validating the Telegram secret token or processing an update body.
Adapter Health Checks
When you use framework adapters, pass the same healthPath option and mount the adapter on both routes where the framework needs it:
import { createExpressMiddleware } from 'vibegram';
const webhook = createExpressMiddleware(bot, {
secretToken: WEBHOOK_SECRET,
healthPath: '/healthz',
});
app.post('/webhook', webhook);
app.get('/healthz', webhook);Deployment Checklist
- Always terminate TLS in front of your webhook endpoint.
- Set a random
secret_tokenwhen callingsetWebhook. - Restrict webhook routes to
POSTonly. - Use JSON body parsing only on the webhook route.
- Keep your bot token and webhook secret outside source control.
- Expose a lightweight health endpoint for load balancers and platform probes.
Adapter Hardening Notes
- Native HTTP adapter rejects non-JSON requests with
415 Unsupported Media Type. - Native HTTP adapter rejects oversized bodies with
413 Payload Too Large. healthPathresponds with200 OKbefore secret validation or update parsing.- All adapters return
500 Internal Server Errorwhen update processing fails. - Invalid or malformed update payloads return
400 Bad Request.
Register the Webhook
await bot.callApi('setWebhook', {
url: 'https://your-domain.com/webhook',
secret_token: WEBHOOK_SECRET,
allowed_updates: ['message', 'callback_query'],
});Without Secret Token
If you don't need secret token validation:
app.post('/webhook', bot.webhookCallback());WARNING
Without a secret token, any client that knows your webhook URL can send fake updates. Always use a secret token in production.
TIP
For native Node.js deployments, set maxBodySizeBytes explicitly if your platform requires a tighter body limit than the default 1 MB.