Skip to content

WebApp Validation

mtgo provides built-in helpers for validating Telegram WebApp (Mini App) initData sent from the client to your server.

One-Shot Validation

go
data, err := telegram.ValidateWebAppData(botToken, initData, 5*time.Minute)
if err != nil {
    http.Error(w, "invalid webapp data", http.StatusUnauthorized)
    return
}
fmt.Printf("User ID: %d\n", data.User.ID)
fmt.Printf("Name: %s\n", data.User.FirstName)

ValidateWebAppData derives the secret key from the bot token and validates in one call.

Reusable Secret Key

For repeated validation, derive the key once and reuse it:

go
secretKey := telegram.CreateWebAppSecretKey(botToken)

// Use across multiple requests
data, err := telegram.ParseWebAppData(secretKey, initData, 5*time.Minute)

The key is computed as HMAC-SHA256("WebAppData", botToken) per the Telegram spec.

WebAppInitData Fields

FieldTypeDescription
QueryIDstringQuery ID for answering WebApp queries
User*WebAppUserUser info (ID, FirstName, LastName, Username, LanguageCode)
ChatTypestring"private", "group", "supergroup", "channel"
ChatInstancestringChat instance identifier
StartParamstringStart parameter from deep link
AuthDatetime.TimeWhen the data was signed
HashstringHMAC hash
Rawmap[string]stringAll raw key-value pairs

Error Handling

go
data, err := telegram.ParseWebAppData(secretKey, initData, maxAge)
if err != nil {
    switch {
    case errors.Is(err, types.ErrWebAppDataOutdated):
        // Data is older than maxAge
    case errors.Is(err, types.ErrWebAppDataMismatch):
        // Hash verification failed — tampered data
    case errors.Is(err, types.ErrWebAppDataInvalid):
        // Malformed data or missing fields
    }
}

maxAge Parameter

  • maxAge > 0 — reject data older than the specified duration
  • maxAge == 0 — skip the age check (useful for debugging)

Answering WebApp Queries

go
client.AnswerWebAppQuery(ctx, &tg.InputBotInlineMessageID{
    DC:     data.DC,
    ID:     data.QueryID,
}, result)

Released under the Apache-2.0 License.