Mini Apps

Перевірка initData

Когда Mini App открывается, Telegram передаёт initData — строку с данными пользователя, чата и параметрами запуска. Эта строка подписана ботом, и ваш бэкенд должен проверить подпись, прежде чем доверять данным.

Структура initData

Строка — это URL-encoded query string:

query_id=abc123&user=%7B%22id%22%3A123456%2C%22first_name%22%3A%22Ivan%22%7D&auth_date=1700000000&hash=abcdef123456...

Поле hash — это HMAC-SHA256 от остальных параметров, отсортированных по ключу. Секретный ключ формируется из токена бота.

Алгоритм проверки

  1. Парсим строку, удаляем параметр hash.
  2. Сортируем оставшиеся пары по ключу (лексикографически).
  3. Склеиваем в строку key=value\n (перевод строки между парами).
  4. Вычисляем secret_key = HMAC_SHA256("WebAppData", bot_token).
  5. Вычисляем calculated_hash = HMAC_SHA256(data_string, secret_key).
  6. Сравниваем calculated_hash с полученным hash (hex-строка).
  7. Проверяем auth_date — не старше 24 часов (или вашего TTL).

PHP-реализация

function verifyInitData(string $initData, string $botToken, int $ttl = 86400): ?array {
    parse_str($initData, $params);
    
    if (!isset($params['hash'])) {
        return null;
    }
    $hash = $params['hash'];
    unset($params['hash']);
    
    ksort($params);
    $dataString = '';
    foreach ($params as $k => $v) {
        $dataString .= $k . '=' . $v . "\n";
    }
    $dataString = rtrim($dataString, "\n");
    
    $secretKey = hash_hmac('sha256', 'WebAppData', $botToken, true);
    $calculatedHash = hash_hmac('sha256', $dataString, $secretKey);
    
    if (!hash_equals($calculatedHash, $hash)) {
        return null;
    }
    
    if (isset($params['auth_date']) && (time() - (int)$params['auth_date'] > $ttl)) {
        return null;
    }
    
    if (isset($params['user'])) {
        $params['user'] = json_decode($params['user'], true);
    }
    
    return $params;
}

// Использование
$initData = $_POST['initData'] ?? '';
$botToken = '123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11';

$userData = verifyInitData($initData, $botToken);
if ($userData === null) {
    http_response_code(401);
    exit('Invalid initData');
}

// $userData['user']['id'], $userData['user']['first_name'] и т.д.

Типичные ошибки

  • Не сортируют параметры — порядок критичен.
  • Используют строковый токен вместо бинарного ключаhash_hmac(..., true) возвращает raw binary для secret_key.
  • Не проверяют auth_date — реплей-атаки.
  • Доверяют user без парсинга JSON — в initData это URL-encoded JSON-строка.

Передача на бэкенд

В Mini App (JS) получаете initData через Telegram.WebApp.initData и отправляете на свой API:

fetch('https://api.example.com/auth', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ initData: Telegram.WebApp.initData })
});

Бэкенд проверяет, создаёт/обновляет пользователя, выдаёт JWT или сессию.

← Что такое Mini App | Дальше: React и Vue →