User login
User accounts log in with a phone number plus a verification code, optionally followed by a two-factor password. The flow is the same gogram uses for everything from one-shot scripts to long-lived userbots.
The flow
The MTProto user-login flow has three steps:
- SendCode: server delivers a code via service message, SMS, or call.
- SignIn: client submits the code with the phone hash from step one.
- CheckPassword if the account has 2FA enabled.
gogram's Login helper wraps all three. Pass a phone number; if the code/password are not supplied up-front, it prompts on stdin.
Interactive login
For local development or first-time setup, the default callbacks read from the terminal:
client.Connect()
ok, err := client.Login("+15551234567")
if err != nil {
log.Fatal(err)
}
if !ok {
log.Fatal("authorization not confirmed")
}client.Connect()
ok, err := client.Login("+15551234567")
if err != nil {
log.Fatal(err)
}
if !ok {
log.Fatal("authorization not confirmed")
}On first run, gogram prints "Enter the code:", waits, then "Enter your 2FA password:" if needed. After a successful login the auth key lands in your session file and every subsequent run skips straight past Login.
Non-interactive login
When the program is not attached to a terminal — CI, server, web handler — provide the code through LoginOptions instead:
code, hash, _ := client.SendCode("+15551234567")
// code arrives via Telegram service messages; deliver "code" to your code
// path however you like (web form, queue, whatever)
ok, err := client.Login("+15551234567", &telegram.LoginOptions{
Code: code,
CodeHash: hash,
Password: os.Getenv("TG_2FA_PASSWORD"),
})code, hash, _ := client.SendCode("+15551234567")
// code arrives via Telegram service messages; deliver "code" to your code
// path however you like (web form, queue, whatever)
ok, err := client.Login("+15551234567", &telegram.LoginOptions{
Code: code,
CodeHash: hash,
Password: os.Getenv("TG_2FA_PASSWORD"),
})Call SendCode first, capture the codeHash, deliver the actual code to your service through whatever channel makes sense (a web form, a queue, a Telegram message to a co-bot), then call Loginwith both. This split lets you separate the "ask Telegram to send a code" step from the "submit the user's answer" step.
Custom code and password callbacks
If you want the prompting logic but not stdin specifically, plug in your own callbacks:
_, err := client.Login("+15551234567", &telegram.LoginOptions{
CodeCallback: func() (string, error) {
// e.g. read from a web form, an SQS queue, etc.
return waitForCode(), nil
},
PasswordCallback: func() (string, error) {
return vault.Get("tg-2fa"), nil
},
OnWrongCode: func(attempt, max int) bool {
log.Printf("invalid code (%d/%d), trying again", attempt, max)
return attempt < max
},
MaxRetries: 3,
})_, err := client.Login("+15551234567", &telegram.LoginOptions{
CodeCallback: func() (string, error) {
// e.g. read from a web form, an SQS queue, etc.
return waitForCode(), nil
},
PasswordCallback: func() (string, error) {
return vault.Get("tg-2fa"), nil
},
OnWrongCode: func(attempt, max int) bool {
log.Printf("invalid code (%d/%d), trying again", attempt, max)
return attempt < max
},
MaxRetries: 3,
})Every callback runs synchronously; block as long as you need. The OnWrongCodeand OnWrongPasswordcallbacks decide whether to retry — return true to try again, false to give up.
Two-factor passwords
If the account has 2FA enabled, after a successful code submission the server replies with SESSION_PASSWORD_NEEDED. gogram intercepts that, calls account.getPasswordto fetch the SRP parameters, hashes the user's password through SRP, and submits auth.checkPassword. You never deal with SRP yourself; you only deliver the cleartext password through the callback or the Passwordfield in LoginOptions.
Common errors
- PHONE_NUMBER_INVALID
- The number is not in E.164 format. Include the leading "+" and country code.
- PHONE_CODE_INVALID
- The code the user entered is wrong. The default
OnWrongCodecallback prompts again. - PHONE_CODE_EXPIRED
- Too much time passed between
SendCodeandSignIn. CallSendCodeagain to refresh. - PASSWORD_HASH_INVALID
- Wrong 2FA password, or the SRP parameters went stale. The client re-fetches and retries automatically; if it still fails, the password is wrong.
- PHONE_NUMBER_BANNED
- The account is banned by Telegram and cannot be used.
- FLOOD_WAIT_X
- Too many login attempts for this phone. Sleep for the supplied seconds.
Every login error lives in the errors database with a longer when-and-why explanation.
