Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Session Persistence

A session stores your auth key, DC address, and peer access-hash cache. Without it, you’d need to log in on every run.

Binary file (default)

#![allow(unused)]
fn main() {
use layer_client::{Client, Config};

let (client, _shutdown) = Client::connect(Config {
    session_path: "my.session".into(),
    api_id:       12345,
    api_hash:     "abc123".into(),
    ..Default::default()
}).await?;
}

After login, save to disk:

#![allow(unused)]
fn main() {
client.save_session().await?;
}

The file is created at session_path and reloaded automatically on the next Client::connect. Keep it in .gitignore — it grants full API access to your account.


In-memory (ephemeral)

Nothing written to disk. Useful for tests or short-lived scripts:

#![allow(unused)]
fn main() {
use layer_client::session_backend::InMemoryBackend;

let (client, _shutdown) = Client::builder()
    .session(InMemoryBackend::new())
    .api_id(12345)
    .api_hash("abc123")
    .connect()
    .await?;
}

Login is required on every run since nothing persists.


SQLite (robust, long-running servers)

layer-client = { version = "0.4.5", features = ["sqlite-session"] }
#![allow(unused)]
fn main() {
let (client, _shutdown) = Client::connect(Config {
    session_path: "session.db".into(),
    ..Default::default()
}).await?;
}

SQLite is more resilient against crash-corruption than the binary format. Ideal for production bots.


String session — New in v0.4.5

Encode the entire session as a portable base64 string. Store it in an env var, a DB column, or CI secrets:

#![allow(unused)]
fn main() {
// Export (after login)
let s = client.export_session_string().await?;
// → "AQAAAAEDAADtE1lMHBT7...=="

// Restore
let (client, _shutdown) = Client::with_string_session(
    &s, api_id, api_hash,
).await?;

// Or via builder
use layer_client::session_backend::StringSessionBackend;
let (client, _shutdown) = Client::builder()
    .session(StringSessionBackend::new(&s))
    .api_id(api_id)
    .api_hash(api_hash)
    .connect()
    .await?;
}

See Session Backends for the full guide including LibSQL (Turso) backend.


What’s stored in a session

FieldDescription
Auth key2048-bit DH-derived key for encryption
Auth key IDHash of the key, used as identifier
DC IDWhich Telegram data center to connect to
DC addressThe IP:port of the DC
Server saltUpdated regularly by Telegram
Sequence numbersFor message ordering
Peer cacheUser/channel access hashes (speeds up API calls)

Security

SECURITY: A stolen session file gives full API access to your account. Protect it like a password.

  • Add to .gitignore: *.session, *.session.db
  • Set restrictive permissions: chmod 600 my.session
  • Never log or print session file contents
  • If compromised: revoke from Telegram → Settings → Devices → Terminate session

Multi-session / multi-account

Each Client::connect loads one session. For multiple accounts, use multiple files:

#![allow(unused)]
fn main() {
let (client_a, _) = Client::connect(Config {
    session_path: "account_a.session".into(),
    api_id, api_hash: api_hash.clone(), ..Default::default()
}).await?;

let (client_b, _) = Client::connect(Config {
    session_path: "account_b.session".into(),
    api_id, api_hash: api_hash.clone(), ..Default::default()
}).await?;
}