How to Add Telegram Login to Your Website
Practice4 minInnovialabs editorial team
In short
Create a bot, link your domain to it in BotFather, embed the widget, then on the server verify the hash using the SHA-256 of the bot token and check that auth_date is fresh — only then create a session.
How it works
The Telegram Login Widget is a "Log in with Telegram" button that Telegram renders on your site. The user confirms the login inside Telegram, and the widget returns:
id— the user's permanent identifier;first_name,last_name,username,photo_url— profile data (some fields may be missing);auth_date— the login time as a Unix timestamp;hash— a signature that lets your server confirm the data came from Telegram.
The key rule: data from the browser means nothing until the server has verified hash. Anyone can craft JSON with someone else's id.
Step 1. Bot and domain
- Create a bot in @BotFather or reuse an existing one. Logins are requested on its behalf.
- Send BotFather the
/setdomaincommand and enter your site's domain. The widget only works on the linked domain. - Keep the bot token in your server's environment variables. It is needed to verify signatures and must never reach the frontend.
For local development the widget needs a real domain, so teams usually use a tunnel or a test subdomain.
Step 2. The widget on the page
There are two modes: a redirect to your URL with data in query parameters, or a JavaScript callback.
<script async src="https://telegram.org/js/telegram-widget.js?22"
data-telegram-login="your_bot"
data-size="large"
data-auth-url="https://example.com/auth/telegram"
data-request-access="write"></script>
data-auth-url— Telegram redirects the user here withid,auth_date,hashand other parameters.- Alternatively, set
data-onauth="onTelegramAuth(user)"and POST theuserobject to your server. data-request-access="write"asks permission for your bot to message the user. Add it if you plan to send notifications.
Step 3. Verify the hash on the server
The algorithm:
- Take every received field except
hash. - Sort them by key and build a string of
key=valuelines joined with\n. - The secret key is the SHA-256 of the bot token (raw bytes).
- Compute HMAC-SHA-256 of the string with that key and compare the hex result to
hash. - Check that
auth_dateis not too old.
import hashlib, hmac, time
def verify_telegram_login(data: dict, bot_token: str, max_age: int = 86400) -> bool:
received_hash = data.pop("hash", "")
check_string = "\n".join(f"{k}={v}" for k, v in sorted(data.items()))
secret = hashlib.sha256(bot_token.encode()).digest()
expected = hmac.new(secret, check_string.encode(), hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, received_hash):
return False
return time.time() - int(data["auth_date"]) < max_age
Details that matter:
- Use constant-time comparison (
hmac.compare_digest,crypto.timingSafeEqual). - Include all received fields in the string, not just the ones you know: Telegram may add new ones.
- Do not confuse this with Mini Apps: there the secret key is derived differently, via HMAC with the key
WebAppData.
Step 4. Linking accounts
Store the link by id, not username: usernames can be changed or removed.
Typical scenarios:
- New user — create an account with a
telegram_id. - Already signed in another way — the user clicks "Connect Telegram" in profile settings, and you attach
telegram_idto the current account. - Has an email account but logs in with Telegram for the first time — do not merge automatically. The widget does not send email or phone, so a matching name proves nothing. Ask the user to sign in the old way and then connect Telegram.
Add a unique index on telegram_id so one Telegram account cannot be attached to two profiles.
Step 5. Sessions
After a successful check, the server creates its own session — Telegram is no longer involved.
- Use a cookie with
HttpOnly,SecureandSameSite=LaxorStrict. - Never use
hashorauth_dateas a session token. - Limit the
auth_datewindow so an intercepted link with parameters cannot be replayed much later. - After the redirect, strip the parameters from the address bar so they do not end up in browser history and logs.
- Let users log out and disconnect Telegram.
Common mistakes
- Trusting data from
onTelegramAuthwithout server-side verification. - The bot token in frontend code.
- Checking only known fields instead of all received ones.
- No
auth_datecheck.