The Authentication Flow
Your frontend creates a session
When the user clicks “Sign in with Telegram”, the Bondify SDK calls
POST /api/v1/generate/public with your project_id. Bondify creates a short-lived session and returns two values:session_token— a unique token you will use to poll for the result.deeplink— ahttps://t.me/...URL that opens your Bondify Telegram bot.
Response
Telegram opens and the bot sends a confirmation prompt
The SDK opens the deeplink in a new tab or redirects the user to the Telegram app. The Bondify bot immediately sends the user a message containing a ✅ Confirm button and a ❌ Cancel button, along with the name of your app so they know what they are authorising.
The user confirms or cancels
The user taps one of the two buttons in Telegram:
- ✅ Confirm — Bondify marks the session as
confirmedand signs a proof JWT. - ❌ Cancel — Bondify marks the session as
cancelled.
Your frontend polls for the result
While the user is in Telegram, your app polls While waiting, the endpoint returns:
POST /api/v1/verify/public every 2 seconds with the session_token. The SDK handles this loop automatically — you only receive the final result in your onSuccess or onError callback.Pending response
Bondify returns the confirmed user and a proof
When the user taps ✅ Confirm, the next poll returns the full result:The SDK surfaces this as a typed
Confirmed response
user object in your onSuccess callback:Session Statuses
Every session moves through a defined lifecycle. Your polling code and webhook handler must handle all five statuses.| Status | Meaning | What to do |
|---|---|---|
pending | Waiting for user action in Telegram | Keep polling every 2 s, show a loading spinner |
confirmed | User tapped ✅ Confirm | Stop polling, send proof to your server, log user in |
cancelled | User tapped ❌ Cancel | Stop polling, show “You declined the request” |
expired | Session not used within 10 minutes | Stop polling, offer the user a “Try again” button |
used | Proof already consumed (verified once) | Do not reuse — generate a fresh session |
Sessions expire automatically after 10 minutes. If a user leaves Telegram open without tapping either button, the session transitions to
expired. Always handle this state in your UI so users are never left on a frozen loading screen.Cryptographic Proof
When a session reachesconfirmed, Bondify signs a JWT using HMAC-SHA256 with your project’s secret key. This proof encodes the user’s telegram_id, name, and username, along with a timestamp and the session token.
You must verify this proof on your server before creating a user session:
verifyProof throws if the signature is invalid, the proof has expired, or the payload is malformed. Never skip this step.
Webhook Alternative
Polling is the default and works in all environments, but if your backend needs to react to auth events without waiting for a client request, you can receive webhooks instead. Configure a webhook URL in your project settings and Bondify willPOST a signed payload to your endpoint the moment a session changes state:
auth.confirmed event
auth.cancelled event
X-Bondify-Signature header containing an HMAC-SHA256 signature of the raw request body. Always verify this signature before processing the event.
Verify webhook signature (Node.js)