$ guides / telegram-bot

Telegram Bot

Implement Telegram user-based licensing with AuthForge using HWID override.

Guide

This pattern lets anyone message your bot, but only licensed users get full responses.

Architecture

  1. User sends a message to your bot.
  2. If not licensed, bot asks for a license key.
  3. User submits key in DM/private chat.
  4. Bot validates key with AuthForge and sets hwidOverride = tg:<telegram_user_id>.
  5. If valid, store “licensed” status for that Telegram user.

Why this works

  • AuthForge treats HWID as an identity string.
  • tg:<user_id> is stable per Telegram account.
  • Seat controls (maxHwidSlots) and reset flows still work.

Use user_id, not username (usernames can change).

Use heartbeatMode: "LOCAL" (or heartbeat_mode="LOCAL" in Python) for the bot process. Server heartbeat mode targets software running on the licensee’s device; a Telegram bot only performs validation on your infrastructure, so local session checks after login are enough.

For every scheduled run or every message, use validateLicense / validate_license (same /auth/validate + Ed25519 verification as login) so you avoid heartbeat timers and never need logout() just to stop background intervals. Keep login for processes that intentionally hold one long-lived session.

Node example (Telegraf-style pseudocode)

import { AuthForgeClient } from "@authforgecc/sdk";

async function validateTelegramKey(telegramUserId, licenseKey) {
  const client = new AuthForgeClient({
    appId: process.env.AUTHFORGE_APP_ID,
    appSecret: process.env.AUTHFORGE_APP_SECRET,
    publicKey: process.env.AUTHFORGE_PUBLIC_KEY,
    heartbeatMode: "LOCAL",
    hwidOverride: `tg:${telegramUserId}`,
  });

  const result = await client.validateLicense(licenseKey);
  return result.valid ? result : { valid: false, code: result.code };
}

Python example

from authforge import AuthForgeClient

def validate_telegram_key(user_id: int, license_key: str) -> dict:
    client = AuthForgeClient(
        app_id=APP_ID,
        app_secret=APP_SECRET,
        public_key=PUBLIC_KEY,
        heartbeat_mode="LOCAL",
        hwid_override=f"tg:{user_id}",
    )
    return client.validate_license(license_key)
  • Keep key entry in private chat.
  • Rate limit invalid attempts per user and per IP.
  • Return clear error text for invalid_key, expired, revoked, hwid_mismatch.
  • Provide a support command to request reset help when users switch accounts.

Contact support

Feel free to reach out if you have questions, need help getting set up, or run into something unexpected. We'll get back to you as soon as we can.

Email us at support@authforge.cc