ptgb
A complete Telegram Bot API client for Dart

Web App Verification

Part of the Examples. Verifying a Telegram Mini App's signed initData with Bot.verifyWebAppInitData.

Source: example/12_web_app_verification.dart

// ignore_for_file: file_names
// (numbered intentionally for reading/run order -- see README.md)

// ============================================================================
// 12 — VERIFYING TELEGRAM MINI APP (WEB APP) DATA
// ============================================================================
//
// If you have a Telegram Mini App (a web page opened inside Telegram via a
// menu button or inline "Web App" button), it sends your backend an
// `initData` string containing the user's info, signed with your bot's
// token. You MUST verify this signature server-side before trusting any of
// it — otherwise anyone could forge a request claiming to be any user.
//
// This example is a minimal HTTP endpoint your Mini App's frontend would
// call right after launch, like:
//
//   fetch('/verify', { method: 'POST', body: Telegram.WebApp.initData })
//
// HOW TO RUN:
//   dart run example/12_web_app_verification.dart   (with a `.env` file)
// ============================================================================

import 'dart:convert';
import 'dart:developer';
import 'dart:io';

import 'package:ptgb/ptgb.dart';

Future<void> main() async {
  final bot = Bot();

  final server = await HttpServer.bind('0.0.0.0', 8080);
  log('Listening for Mini App verification requests on :8080/verify');

  await for (final request in server) {
    if (request.method != 'POST' || request.uri.path != '/verify') {
      request.response.statusCode = HttpStatus.notFound;
      await request.response.close();
      continue;
    }

    final initData = await utf8.decoder.bind(request).join();

    // This does the actual HMAC-SHA256 verification against your bot token.
    final parsed = bot.verifyWebAppInitData(initData);

    if (!parsed.isValid) {
      // Never trust unverified data — reject it outright.
      request.response.statusCode = HttpStatus.unauthorized;
      request.response.write(jsonEncode({'error': 'invalid signature'}));
      await request.response.close();
      continue;
    }

    // Safe to use now — `parsed.user` is the verified Telegram user object.
    final user = parsed.user;
    request.response
      ..statusCode = HttpStatus.ok
      ..headers.contentType = ContentType.json
      ..write(jsonEncode({
        'ok': true,
        'userId': user?['id'],
        'firstName': user?['first_name'],
        'authenticatedAt': parsed.authDate?.toIso8601String(),
      }),);
    await request.response.close();
  }
}

Run it from the package root:

dart run example/12_web_app_verification.dart