Skip to main content
Bondify is designed so that every confirmed authentication event is cryptographically verifiable. By signing proofs with your project’s secret key, Bondify ensures that no client-side code — and no attacker — can fabricate a login event without access to a key that only your server holds. This page explains how that mechanism works and what you need to do to keep it airtight.

How cryptographic proof works

When a user taps ✅ Confirm in Telegram, Bondify generates a proof — a JWT signed with your project’s secret key using HMAC-SHA256. This proof encodes the user’s Telegram identity and the session metadata, and its signature can only be produced by someone who knows your secret key. Your server verifies the proof by calling verifyProof() from @bondify/server:
import { verifyProof } from '@bondify/server';

const user = await verifyProof(proof, process.env.BONDIFY_SECRET_KEY!);
// user.telegramId, user.name — safe to trust only after this call
If the proof has been tampered with, forged, or signed with a different key, verifyProof() throws. You should catch that error, return a 401, and log the attempt.
Never trust telegram_id, telegram_name, or any other identity data passed directly from the client without first verifying the proof server-side. Client-supplied values can be freely fabricated. Only values returned by a successful verifyProof() call are trustworthy.

Security checklist

Work through each item below before going to production:
1

Never commit your Secret Key to version control

Store your Secret Key exclusively in environment variables (e.g., BONDIFY_SECRET_KEY=sk_live_...). Use a secrets manager (AWS Secrets Manager, HashiCorp Vault, Doppler, etc.) for production deployments. A committed key is a compromised key.
2

Never embed the Secret Key in client-side code

The Secret Key belongs on your server — never in the browser, React/Vue/Angular bundles, React Native apps, Flutter apps, or any code that ships to a user’s device. Use the public-facing project_id in client code and reserve the secret key for your backend only.
3

Always verify the proof server-side

Call verifyProof(proof, secretKey) on your server before creating any user session, writing to your database, or granting any access. Skipping verification means any attacker can log in as anyone by supplying a fake telegram_id.
4

Always verify webhook signatures

Every webhook request from Bondify includes an X-Bondify-Signature header containing an HMAC-SHA256 hex digest of the request body. Verify it before processing any webhook event:
import crypto from 'crypto';

// Use the raw request body bytes — not re-serialised JSON
const sig      = req.headers['x-bondify-signature'] as string;
const expected = crypto
  .createHmac('sha256', process.env.BONDIFY_SECRET_KEY!)
  .update(rawBody) // rawBody = req.body.toString() captured before JSON parsing
  .digest('hex');

if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
  return res.status(401).end();
}
5

Handle all terminal session statuses in your UI

Always handle cancelled and expired statuses gracefully — stop polling and show the user a clear message. Leaving these states unhandled can result in a broken UI that a confused user may abandon or, worse, retry in ways that create unexpected states.
6

Use HTTPS only in production

All Bondify SDKs assume secure transport. Serving your app over plain HTTP in production means proofs and tokens can be intercepted in transit.
7

Never reuse expired or used session tokens

Sessions expire after 10 minutes. A session with status expired or used cannot be revived. Generate a fresh session for each new login attempt — never reuse a token.
8

Rotate your Secret Key if it is compromised

If your Secret Key is ever accidentally exposed (committed to git, logged, leaked via an error message), go to your project settings immediately and click Regenerate key. Then update BONDIFY_SECRET_KEY on all servers and redeploy. The old key is invalidated the moment you regenerate.

Secrets management

Your Secret Key (sk_live_...) must be kept server-side at all times. If it is ever exposed — in source code, logs, error responses, or anywhere else — rotate it immediately from the Bondify dashboard and redeploy your services with the new key.
Recommended environment variable names:
# .env (server-side only — never committed to git)
BONDIFY_SECRET_KEY=sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
NEXT_PUBLIC_BONDIFY_PROJECT_ID=proj_xxxxxxxx   # safe for client-side use
Use separate projects for staging and production, each with its own secret key. That way a key rotation or misconfiguration in staging never affects your live users, and you can safely test your rotation runbook before you ever need it in production.

What Bondify protects against

Fake auth events

Every confirmed event carries an HMAC-SHA256 signed proof. An attacker cannot fabricate a valid proof without your secret key — even if they intercept a real proof in transit.

Replay attacks

Sessions are single-use. Once a proof is consumed by verifyProof(), the session moves to used and the same proof cannot be replayed to log in again.

Identity impersonation

The telegram_id inside a proof is bound to the Telegram account that actually confirmed the session. Telegram’s own account verification ensures the identity is real — Bondify’s signature ensures it wasn’t tampered with on the way to your server.

Unsigned webhook events

Every webhook payload is signed with your secret key. Your server can reject any unsigned or incorrectly signed request before it touches your business logic.

Next steps

Authentication Flow

See exactly where verifyProof() fits in the end-to-end flow.

Projects

Learn how to rotate your secret key from the project settings page.