telega_webapp

Telegram Mini Apps (Web Apps) support for Telega.

A Mini App receives a signed initData string from the Telegram client. Your backend must verify that string before trusting any of the user data inside it. This module covers the full server-side flow:

Validation

The signing scheme (see the official docs): secret_key = HMAC_SHA256(bot_token, "WebAppData"), then the expected hash is HMAC_SHA256(data_check_string, secret_key) where data_check_string is every field except hash/signature, sorted by key and joined with newlines as key=value.

import telega_webapp

// `init_data` is the raw query string from `Telegram.WebApp.initData`,
// forwarded by your frontend (e.g. in an `Authorization` header).
case telega_webapp.validate_with_max_age(token, init_data, 86_400) {
  Ok(data) -> {
    // Trusted. `data.user` is who opened the app.
    todo
  }
  Error(_) -> todo  // reject the request
}

Types

Which Telegram environment a third-party signature was issued by. Selects the public key used for Ed25519 verification.

pub type Environment {
  Production
  Test
}

Constructors

  • Production
  • Test

A chat the Mini App was launched from (attachment-menu apps only).

Mirrors the WebAppChat object.

pub type WebAppChat {
  WebAppChat(
    id: Int,
    type_: String,
    title: String,
    username: option.Option(String),
    photo_url: option.Option(String),
  )
}

Constructors

Reasons validation or parsing can fail.

pub type WebAppError {
  MalformedInitData
  InvalidField(String)
  MissingHash
  MissingSignature
  SignatureMismatch
  Outdated
}

Constructors

  • MalformedInitData

    The initData string is not a valid URL-encoded query.

  • InvalidField(String)

    A required field (named) was missing or could not be decoded.

  • MissingHash

    No hash field — cannot run first-party validation.

  • MissingSignature

    No signature field — cannot run third-party validation.

  • SignatureMismatch

    The computed signature did not match the provided one.

  • Outdated

    auth_date is older than the allowed max_age.

The decoded initData payload.

hash is the first-party HMAC-SHA256 signature and is empty when the app was opened with only a third-party signature present.

pub type WebAppInitData {
  WebAppInitData(
    query_id: option.Option(String),
    user: option.Option(WebAppUser),
    receiver: option.Option(WebAppUser),
    chat: option.Option(WebAppChat),
    chat_type: option.Option(String),
    chat_instance: option.Option(String),
    start_param: option.Option(String),
    can_send_after: option.Option(Int),
    auth_date: Int,
    hash: String,
    signature: option.Option(String),
  )
}

Constructors

A Telegram user as described inside a Mini App initData payload.

Mirrors the WebAppUser object — note this is not the same shape as the Bot API User.

pub type WebAppUser {
  WebAppUser(
    id: Int,
    first_name: String,
    last_name: option.Option(String),
    username: option.Option(String),
    language_code: option.Option(String),
    is_bot: option.Option(Bool),
    is_premium: option.Option(Bool),
    added_to_attachment_menu: option.Option(Bool),
    allows_write_to_pm: option.Option(Bool),
    photo_url: option.Option(String),
  )
}

Constructors

Values

pub fn answer_web_app_query(
  client client: client.TelegramClient,
  web_app_query_id web_app_query_id: String,
  result result: types.InlineQueryResult,
) -> Result(types.SentWebAppMessage, error.TelegaError)

Reply to an inline Mini App query via answerWebAppQuery.

web_app_query_id comes from the web_app_data/WebAppData query sent by the app; build result with telega/inline_mode or the raw telega/model/types constructors.

pub fn is_fresh(
  data data: WebAppInitData,
  max_age_seconds max_age_seconds: Int,
  now_unix now_unix: Int,
) -> Bool

Whether auth_date is within max_age_seconds of now_unix (both in Unix seconds). Exposed for callers that supply their own clock.

pub fn parse(
  init_data init_data: String,
) -> Result(WebAppInitData, WebAppError)

Decode init_data into typed values without verifying any signature.

Only use on input you have already validated (or trust for another reason); for request handling use validate instead.

pub fn validate(
  token token: String,
  init_data init_data: String,
) -> Result(WebAppInitData, WebAppError)

Validate init_data against your bot token using the first-party HMAC-SHA256 scheme and return the typed payload on success.

This does not check auth_date freshness — use validate_with_max_age to also reject stale data, which you almost always want in production.

pub fn validate_third_party(
  bot_id bot_id: Int,
  init_data init_data: String,
  environment environment: Environment,
) -> Result(WebAppInitData, WebAppError)

Validate init_data issued for a third-party bot using the Ed25519 signature field. bot_id is the numeric id of the bot the Mini App was opened for (the part before : in its token).

Use this when your service receives Mini App data for bots you don’t hold the token of; otherwise prefer validate.

pub fn validate_with_max_age(
  token token: String,
  init_data init_data: String,
  max_age_seconds max_age_seconds: Int,
) -> Result(WebAppInitData, WebAppError)

Like validate, but also rejects data whose auth_date is older than max_age_seconds relative to the current system time.

A typical max_age is one day (86_400).

Search Document