Developing Telegram Login Authentication
Telegram Login is non-standard OAuth. Telegram has no OIDC-compliant provider, no familiar Authorization Code Flow. Instead — custom widget/protocol with cryptographic verification via HMAC-SHA256. This requires careful implementation on server side and several client variants depending on task.
Two Telegram Login Variants for Mobile Apps
Telegram Login Widget — JavaScript widget for web, opened in WebView inside app. User taps "Sign in via Telegram", popup or QR appears, user confirms in Telegram app. Callback comes to WebView with user data. Simplest variant, minimal code.
Telegram Bot + Deep Link — more native approach for mobile. Bot generates one-time link tg://resolve?domain=YOUR_BOT&start=AUTH_TOKEN. App opens this link — system opens Telegram with bot chat. User taps Start, bot gets /start AUTH_TOKEN message via Webhook, verifies token, calls your API. App waits for callback via WebSocket or polling.
Second variant more complex architecturally, but gives fully native UX: Telegram opens as regular app via Universal Link, not WebView.
Cryptographic Data Verification
This is the most important part of Telegram Login. Data Telegram gives client (id, username, first_name, hash, auth_date) must be verified on server — otherwise attacker can fake authorization.
Verification algorithm:
# Python (server side)
import hashlib
import hmac
def verify_telegram_auth(bot_token: str, auth_data: dict) -> bool:
check_hash = auth_data.pop('hash')
# String for verification: sorted key=value pairs via \n
data_check_string = '\n'.join(
f'{k}={v}' for k, v in sorted(auth_data.items())
)
# Secret — SHA256 of bot token (not the token itself)
secret_key = hashlib.sha256(bot_token.encode()).digest()
# HMAC-SHA256
calculated_hash = hmac.new(
secret_key,
data_check_string.encode(),
hashlib.sha256
).hexdigest()
# Check hash and data freshness (not older than 24 hours)
return (calculated_hash == check_hash and
time.time() - int(auth_data['auth_date']) < 86400)
bot_token must be only on server — never in mobile client. Client passes entire Telegram data set to backend, backend verifies.
WebView Variant Implementation
On mobile client simpler: load HTML page with Telegram Login Widget in WKWebView (iOS) / WebView (Android). Page reports result via window.postMessage or URL redirect on custom scheme.
// iOS — redirect handling from WebView
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
if let url = navigationAction.request.url,
url.scheme == "myapp",
url.host == "telegram-callback" {
// Parse query params — Telegram data
let components = URLComponents(url: url, resolvingAgainstBaseURL: false)
let params = components?.queryItems?.reduce([String:String]()) { ... }
handleTelegramAuth(params)
decisionHandler(.cancel)
return
}
decisionHandler(.allow)
}
Limitations and Edge Cases
Telegram Login requires domain binding: when creating widget or setting up bot, specify domain where authorization allowed. For mobile app without web version this is artificial constraint — need to register any controlled domain and place interim page on it.
User without Telegram on device: when opening tg:// link — nothing happens. Need fallback: offer to download Telegram or switch to other login method.
Telegram account doesn't always have username (it's optional). first_name — always exists. Email — Telegram never transmits.
Timeline: 1 to 2 weeks. WebView variant — closer to week. Native Deep Link via bot — up to two weeks with server part (Webhook, WebSocket for callback).







