Authentication

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:

  1. SendCode: server delivers a code via service message, SMS, or call.
  2. SignIn: client submits the code with the phone hash from step one.
  3. 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 OnWrongCode callback prompts again.
PHONE_CODE_EXPIRED
Too much time passed between SendCode and SignIn. Call SendCode again 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.