gram-js / gramjs

NodeJS/Browser MTProto API Telegram client library,
MIT License
1.33k stars 182 forks source link

Login with session logout me on all devices #452

Open tinkerbaj opened 1 year ago

tinkerbaj commented 1 year ago

When I try to login with number and code and save session it log me out from all devices (phone, pc)

ncesar commented 1 year ago

How are you trying to login? I'm able to keep all my sessions.

sample code:

  console.log('Loading interactive example...');
  const client = new TelegramClient(stringSession, apiId, apiHash, {
    connectionRetries: 5,
  });
  await client.start({
    phoneNumber: async () => await input.text('Please enter your number: '),
    password: async () => await input.text('Please enter your password: '),
    phoneCode: async () =>
      await input.text('Please enter the code you received: '),
    onError: (err) => console.log(err),
  });
  console.log('You should now be connected.');
  console.log(client.session.save()); // Save this string to avoid logging in again
AgentBelfort commented 1 year ago

same issue

nmonokov commented 1 year ago

Same for me and i got my account suspended for several attempts. After first signin in the code, i've got signed out on every device, i've tried to login once again and got signed out after several minutes even after stoping the node process. So, i'm currently praying my account gets unsuspended.

0x416e6f6e commented 1 year ago

Same. I used the code from the example. At first login everything was ok, but when I used the saved session string, this issue happened.

import { TelegramClient } from "telegram";
import { StringSession } from "telegram/sessions";
import input from "input";

const apiId = 123456;
const apiHash = "123456abcdfg";
const stringSession = new StringSession(""); // fill this later with the value from session.save()

(async () => {
  console.log("Loading interactive example...");
  const client = new TelegramClient(stringSession, apiId, apiHash, {
    connectionRetries: 5,
  });
  await client.start({
    phoneNumber: async () => await input.text("Please enter your number: "),
    password: async () => await input.text("Please enter your password: "),
    phoneCode: async () =>
      await input.text("Please enter the code you received: "),
    onError: (err) => console.log(err),
  });
  console.log("You should now be connected.");
  console.log(client.session.save()); // Save this string to avoid logging in again
  await client.sendMessage("me", { message: "Hello!" });
})();

Moreover, some time ago I lost access to my sim card, and used active sessions for new authentications, and now it's lost too. So sad.

Also, I can't reproduce it with another account.

Sparky-web commented 1 year ago

Same here, using session string.

const client = new TelegramClient(stringSession, config.API_ID, config.API_HASH, {connectionRetries: 5})
await client.start({
    phoneNumber: async () => await input.text('number ?'),
    password: async () => await input.text('password?'),
    phoneCode: async () => await input.text('Code ?'),
    onError: (err) => console.error(err),
});

(!) Also, in between login attempts, all messages I sent to other people that day were deleted. This is really concerning...

KappyJS commented 1 year ago

same problem

VACincoming commented 1 year ago

Same problem. Any solutions/ideas why it happens?

UPD: I found some solution, it may be helpful for somebody. I changed my auth structure to auth via QR and it allows me to sign in without logging out from other devices even though I had a ban for a flood. https://github.com/gram-js/gramjs/issues/248#issuecomment-1032077248

k-g-a commented 1 year ago

Same issue here, neither phone code nor QR code flows save from this. Approximately 10-20 seconds after logging in (as user, not bot), all other sessions on any devices are terminated.

I've also tried to specify DC/IP/port (provided via the application page UI) manually using sessionString.setDC(...) before making a connection - does not help either.

My last guess is to use different accounts: the one thich is used to create an application (and obtain apiId/apiHash) and the one being used for login purpose. But there is no evidence that those must be different for things to work properly, it's just an assumption.

It would be great to hear any clues.

Getsumi3 commented 1 year ago

I encountered a similar behavior (nodejs). I used the code form the example. The only thing that I changed is switched from StringSession to StoreSession.

It worked well on Linux, but when I tried it on Windows I got logged out from all my devices. After I tried to login again I wasn't able to receive login code anymore (no errors). After 5 attempts I got FloodWaitError (expected outcome)

It's been ~5 days and for some reason I still can't receive login code for the account I used.

k-g-a commented 1 year ago

Unfortinately, the guess was wrong. I made the second acocunt and launched the application on it's behalf (apiId/apiHash). After that I tried to login via the first account - the one i had used previously. As a result, the first account was logged out from all the devices once again.

Running node on windows 10, btw. But can`t figure out the root cause of the behaviour. I even can send messages (tried to send a message for myself) and iterate over dialogs, but for several seconds only. Does not matter if I use code or QR flow.

k-g-a commented 1 year ago

Running on the same machine "a random OSS telgram web client using gramjs under the hood" (same apiId/apiHash) - works like a charm. It seems like running an application in nodejs is what makes the session "suspicious" (from the tg serves point of view) causing session termination.

k-g-a commented 1 year ago

Ок, due to severe login limits per day (5 times within 24h), I had to break the golden rule and combine multiple fixes at once, so i'm not 100% sure, which one actually made it:

1) used different accounts for application connection and authorization (this alone had been tried before - no luck); 2) set up TelegramClient options, specifically deviceModel/systemVersion/appVersion (example below) - this one was the only difference between my application and the web client (from my previous message) source code, which ran successfully; the theory behind this is that without those strings telegram serves "mark" your connection as suspicious (going to spam, etc) and revoke session; 3) changed my first call from client.getMe(true) which invokes request for user's UserPeer to client.getMe(false) which invokes request for User (getFullUser under the hood) - this one is the first request made by the working webclient and also is the one which is sent in case of session errors; so the theory was that it's crucial for the application lifecycle, maybe it's "binding" you session at server or something like that; 4) in my desktop client, running on the same machine, I logged out from the account i was going to use for authorization.

The last one seems to be the key. I decided to log out because of the following incident. On the same machine I had: desktop client with "account for application" logged in, webclient running on behalf of "account for application" with "account for authorization" logged in and running smoothly. As soon as I decided to log into webclient as "account for application" - it terminated all the sessions within 10-15 second (same as it happens in this issue). So this made me think, that, maybe, two clients (i.e. desktop + web, desktop + node application, web + node application etc.) can not co-exist on one device.

TL;DR It seems to be necessary (but, maybe, not sufficient) not to use the same account within two clients on the same machine - log out from all the rest before starting your application. You must be logged on some other device (i.e. phone) to recive code/scan QR.

EDIT: the above is not necessary, at least for the case when you have sessionHash. The key seems to be setting additional properties on TelegramClient upon initialization. Refer to my last comment.

If this alone does not help - try all the 4 steps from the guide above.

If few more people confirm success, this issue may be closed.

P.S. Client config example:

const client = new TelegramClient(stringSession, apiId, apiHash, {
  deviceModel: `${APP_NAME}@${DEVICE_NAME}`,
  systemVersion: os.version() || 'Unknown',
  appVersion: `0.2-beta`,
  useWSS: true, // not sure if it works in node at all
  testServers: false, // this one should be the default for node env, but who knows for sure :)
  connectionRetries: 10, // just doubled the value from an example
});
Donomas commented 1 year ago

Подтверждаю, если использовать параметры deviceModel etc. То выход из устройств не происходит

k-g-a commented 1 year ago

After being able to experiment more, it seems like setting deviceModel, + systemVersion + appVersion to something meaningfull solves the session termination problem.

Could even log in with the same number authorized in telegram desktop on the same device.

Vadavur commented 1 year ago

Confirm, setting deviceModel + systemVersion + appVersion worked for me too.

I think, it would have been great to add it to the basic quick start code example, as many people have to deal with the same issue.

VACincoming commented 1 year ago

Sorry guys for the maybe obvious question, but where I should take values for APP_NAME & DEVICE_NAME?) Should it be some random values or I should somewhere find these values?

Vadavur commented 1 year ago

Sorry guys for the maybe obvious question, but where I should take values for APP_NAME & DEVICE_NAME?) Should it be some random values or I should somewhere find these values?

Hi, I made it this way:

import os from 'os';
import { readFile } from 'fs/promises';

const pkg = JSON.parse(await readFile(new URL('./package.json', import.meta.url)));

const client = new TelegramClient(stringSession, apiId, apiHash, {
  deviceModel: `${pkg.name}@${os.hostname()}`,
  systemVersion: os.version() || 'Unknown',
  appVersion: pkg.version,
  useWSS: true,
  testServers: false,
  connectionRetries: 5,
}

And it works fine for me, but I didn't experiment much with that and I suppose you can put there almost anything you like, and the important thing is not to change it during subsequent connections.

Would've been great if someone could clarify this one with knowing (not supposing like me)

SamuiRo commented 1 year ago

2. set up TelegramClient options, specifically deviceModel/systemVersion/appVersion (example below) - this one was the only difference between my application and the web client (from my previous message) source code, which ran successfully; the theory behind this is that without those strings telegram serves "mark" your connection as suspicious (going to spam, etc) and revoke session;

This work for me. Adding deviceModel and others solve the problem

My JS sample

const os = require("os")
const input = require("input")
const { TelegramClient } = require("telegram")
const { StringSession } = require("telegram/sessions")

const pkg = require("./../package.json")
const { SESSION, API_ID, API_HASH } = require("./../config/telegram-config")

const stringSession = new StringSession(SESSION) 
const client_options = {
    deviceModel: `${pkg.name}@${os.hostname()}`,
    systemVersion: os.version() || "Unknown node",
    appVersion: pkg.version,
    useWSS: true, 
    testServers: false,
    connectionRetries: 5
}

async function launch() {
    console.log("Launch")
    const client = new TelegramClient(stringSession, API_ID, API_HASH, client_options)
    await client.start({
        phoneNumber: async () => await input.text("number ?"),
        password: async () => await input.text("password ?"),
        phoneCode: async () => await input.text("code ?"),
        onError: (err) => console.log(err),
    })
}
Fa4stik commented 1 year ago

Ок, due to severe login limits per day (5 times within 24h), I had to break the golden rule and combine multiple fixes at once, so i'm not 100% sure, which one actually made it:

1. used different accounts for application connection and authorization (this alone had been tried before - no luck);

2. set up `TelegramClient` options, specifically `deviceModel`/`systemVersion`/`appVersion` (example below) - this one was the only difference between my application and the web client (from my previous message) source code, which ran successfully; the theory behind this is that without those strings telegram serves "mark" your connection as suspicious (going to spam, etc) and revoke session;

3. changed my first call from `client.getMe(true)` which invokes request for user's `UserPeer` to `client.getMe(false)` which invokes request for `User` (`getFullUser` under the hood) - this one is the first request made by the working webclient and also is the one which is sent in case of session errors; so the theory was that it's crucial for the application lifecycle, maybe it's "binding" you session at server or something like that;

4. in my desktop client, running on the same machine, I logged out from the account i was going to use for authorization.

The last one seems to be the key. I decided to log out because of the following incident. On the same machine I had: desktop client with "account for application" logged in, webclient running on behalf of "account for application" with "account for authorization" logged in and running smoothly. As soon as I decided to log into webclient as "account for application" - it terminated all the sessions within 10-15 second (same as it happens in this issue). So this made me think, that, maybe, two clients (i.e. desktop + web, desktop + node application, web + node application etc.) can not co-exist on one device.

TL;DR ~It seems to be necessary (but, maybe, not sufficient) not to use the same account within two clients on the same machine - log out from all the rest before starting your application. You must be logged on some other device (i.e. phone) to recive code/scan QR.~

EDIT: the above is not necessary, at least for the case when you have sessionHash. The key seems to be setting additional properties on TelegramClient upon initialization. Refer to my last comment.

If this alone does not help - try all the 4 steps from the guide above.

If few more people confirm success, this issue may be closed.

P.S. Client config example:

const client = new TelegramClient(stringSession, apiId, apiHash, {
  deviceModel: `${APP_NAME}@${DEVICE_NAME}`,
  systemVersion: os.version() || 'Unknown',
  appVersion: `0.2-beta`,
  useWSS: true, // not sure if it works in node at all
  testServers: false, // this one should be the default for node env, but who knows for sure :)
  connectionRetries: 10, // just doubled the value from an example
});

Thanks a loot, all work! You best man!!!

IvanMMM commented 9 months ago

Looks like this issue is back again. Here's my input, may be you can find it useful. I'm trying to find reliable way of logging in into account. I got banned in several minutes (no spam ofc). I do not join any groups or anything, just logging in. It happened several times with my own accounts (Indonesian real simcard) so I switched to purchased accounts (.json and .session files). So I restore auth_key as well as account data from this and load pre-created session with code below:

    const {session, dcId, serverAddress} = sessionFile;
    const {deviceModel, systemVersion, appVersion, langPack, systemLangPack} = jsonFile;

    const authKey = new AuthKey();
    await authKey.setKey(session); // Load auth_key (Buffer256) from .session
    const authSession = new MemorySession();
    authSession.setDC(dcId, serverAddress, 443); // Load DC data from .session
    authSession.setAuthKey(authKey, dcId);
    authSession.takeoutId = null;
    authSession.save();

    const clientParams: TelegramClientParams = {
      connectionRetries: 10,
      retryDelay: 5000,
      useWSS: true,
      deviceModel: deviceModel, // Load from .json
      systemVersion: systemVersion, // Load from .json
      appVersion: appVersion, // Load from .json
      langCode: langPack, // Load from .json
      systemLangCode: systemLangPack, // Load from .json
      testServers: false,
    };

    // I use socks 5 proxy
    if (account.proxy && isValidProxy(account.proxy)) {
      clientParams.proxy = account.proxy;
      clientParams.useWSS = false;
    }

Some of accounts can successfully restore session, but they getting banned pretty soon, within 10 minutes. Any bright ideas what could it be?