QR login
QR login is what the Telegram desktop app uses on its log-in screen. Show a QR code, the user scans it from their phone, your client is authenticated.
Why QR
Compared to phone+code, QR login has two advantages: no code to type and no SMS or service message that could be intercepted. The user authorises a new session from inside an already-authenticated client, which makes it the recommended flow for second devices and web sign-ins.
Generating the token
client.Connect()
qr, err := client.QRLogin()
if err != nil {
log.Fatal(err)
}
fmt.Println("scan this URL with the Telegram app:")
fmt.Println(qr.URL())
if err := qr.Wait(); err != nil {
log.Fatal(err)
}
log.Println("logged in")client.Connect()
qr, err := client.QRLogin()
if err != nil {
log.Fatal(err)
}
fmt.Println("scan this URL with the Telegram app:")
fmt.Println(qr.URL())
if err := qr.Wait(); err != nil {
log.Fatal(err)
}
log.Println("logged in")QRLogin calls auth.exportLoginToken and returns a *QrToken with three things: URL() returns the tg://login?token=... URL that encodes the token, Token() returns the raw token bytes (handy if you render the QR yourself), and Wait() blocks until either the token is accepted, the user denies the request, or the token expires.
Rendering the QR
Encode qr.URL() with any QR-code library. In the terminal: qrterminal draws coloured cells. In a web app: pass the URL to your front-end and render with qrcodejs or an SVG generator. In a TUI: go-qrcode.
Waiting for the scan
qr.Wait() polls the server. Telegram pushes updateLoginToken when the user approves or denies the request, and gogram translates that into the return value of Wait.
The token has a server-side TTL of about 30 seconds; gogram refreshes it automatically until Timeout elapses:
qr, _ := client.QRLogin(telegram.QrOptions{
Timeout: 5 * time.Minute,
})qr, _ := client.QRLogin(telegram.QrOptions{
Timeout: 5 * time.Minute,
})Two-factor on top
If the account has a cloud password, scanning the QR is only half the auth — the user still has to enter the 2FA password somewhere. Provide it ahead of time and gogram passes it through the SRP check:
qr, _ := client.QRLogin(telegram.QrOptions{
Password: os.Getenv("TG_2FA_PASSWORD"),
})qr, _ := client.QRLogin(telegram.QrOptions{
Password: os.Getenv("TG_2FA_PASSWORD"),
})Without Password, Wait returns a SESSION_PASSWORD_NEEDED error and you can prompt the user before calling CheckPassword.
