Two-factor passwords
Telegram's cloud password is a second factor that sits on top of the code-by-SMS flow. gogram handles the SRP dance for you; you only ever deliver the cleartext password.
What 2FA is
The cloud password is set in the official client under Settings → Privacy and Security → Two-Step Verification. Once enabled, every new session needs both the phone code and the password before it is authorised. Internally Telegram uses SRP-6a so the password never leaves the device in plain form — the server stores a salted verifier and the client proves knowledge without revealing the secret.
gogram does the SRP work for you. You provide the cleartext, the library hashes it with the server-supplied salt, derives the proof, and submits it.
During login
Both Login and QRLogin accept the password up front. When you already know it (env var, vault, web form), pass it through LoginOptions / QrOptions and the call returns once both factors are accepted.
_, err := client.Login("+15551234567", &telegram.LoginOptions{
Password: os.Getenv("TG_2FA_PASSWORD"),
})_, err := client.Login("+15551234567", &telegram.LoginOptions{
Password: os.Getenv("TG_2FA_PASSWORD"),
})qr, _ := client.QRLogin(telegram.QrOptions{
Password: os.Getenv("TG_2FA_PASSWORD"),
})
_ = qr.Wait()qr, _ := client.QRLogin(telegram.QrOptions{
Password: os.Getenv("TG_2FA_PASSWORD"),
})
_ = qr.Wait()When you do not know the password up front, the default callbacks handle the prompt through stdin. For server-side flows, plug in a custom PasswordCallback on LoginOptions:
_, err := client.Login(phone, &telegram.LoginOptions{
PasswordCallback: func() (string, error) {
return vault.Get("tg-2fa"), nil
},
})_, err := client.Login(phone, &telegram.LoginOptions{
PasswordCallback: func() (string, error) {
return vault.Get("tg-2fa"), nil
},
})Enabling and changing
Setting and rotating the cloud password from the client side requires hitting the raw account.updatePasswordSettingsTL method — gogram exposes it via the generated method on *Client. There is no convenience wrapper like client.PasswordSet at the time of writing. The flow is:
- Call
account.getPasswordto fetch the current SRP parameters. - Derive the SRP check using the cleartext current password (or empty bytes if no password is set yet).
- Build a new SRP verifier from the new cleartext password and the server-supplied algorithm + salts.
- Submit both with
account.updatePasswordSettings.
That is enough work that most projects either keep cloud passwords managed manually through an official client or pin a known-good password generation routine in a small helper. Either approach is fine; the security boundary is identical because the cleartext password is what matters, not how the SRP fields were derived.
SESSION_PASSWORD_NEEDED
When you see this error in any context other than the login flow, something has touched the account's 2FA configuration since your session was created. Re-authenticate with the current password and you are back in.
