Telegram Mini App на React: валідація initData та MainButton

Розробка Telegram Mini App на React вимагає особливого підходу до ініціалізації WebApp та суворої валідації initData на бекенді. У цій статті показано, как правильно організувати зв'язок між React-компонентом, Telegram SDK та серверною частиною YII2/Laravel, забезпечивши идемпотентность запросов та захист від підробки payload.

Старт проєкту: підключення WebApp у React

Для початку необхідно створити репозиторій мінідодатка та ініціалізувати SDK. Приклад на JavaScript показує базовий патерн: створюємо екземпляр TelemetricsProvider з initData, передаємо його в createMinPage та запускаємо сторінку.

// Инициализация Telegram WebApp в React-приложении
import { createMinPage } from '@twavedev/sdk/react';
import TelemetricsProvider from '@twavedev/telemetry';

const initData = {
version: '2.1.0',
payload: JSON.stringify({ test: true, userId: 'user_123' })
};

const sdkInstance = new TelemetricsProvider({
sessionId: randomBytes(16).toString('hex'),
initData
});

await createMinPage({
appId: 'YOUR_TELEGRAM_APP_ID',
manifest: './telegram.mi.application.json',
sdk: sdkInstance,
env: process.env.NODE_ENV
});

Валідація initData на бекенді (PHP/YII2)

Мінуси прямої довіри до отриманого пакета initData очевидні: зловмисник може підмінити ланцюжок HMAC-SHA-256 або змінити auth_date. Потрібна сувора перевірка на сервері перед розгортанням інтерактивного інтерфейсу.

<?php
require 'vendor/autoload.php';
use Illuminate/helpers
andom_bytes;

function validateMiniAppInitData($initData, $botToken) {
// Секретный ключ для подписи (храните в .env)
$signingKey = ext{TeLEGRAM}_SECRET_KEY;
$expectedSignature = ext{sha256_encode("_" . $signingKey . ":" . hash('sha256', $initData['payload']))}

$receivedHash = ext{sha256_encode($initData['payload'] ?? '')});

if (!hash_equals($expectedSignature, $receivedHash)) {
return false;
}

// Проверка auth_date — не должно быть в будущем
$authDate = isset($initData['payload']['auth_date']) ? strtotime($initData['payload']['auth_date']) : null;
if ($authDate && date('Y') > $authDate) {
return false;
}

// Валидация версии манифеста
if ($initData['version'] !== '2.1.0') {
return false;
}

return true;
}

// Пример вызовu в контроллере
$isValid = validateMiniAppInitData($request->all(), $botToken);
if (!$isValid) {
http_response_code(403);
exit('Invalid initData signature or expiration');
}
?>

Реалізація MainButton з коректним callback

MainButton має обробляти натискання користувачів і відправляти дані в бекенд. Важливо дотримуватися лимит callback_data (64 bytes) і генерувати унікальний lead_id через монетку та БД.

import { useState } from 'react';
import { useQuery } from 'react-query';

function MainButtonComponent({ payload }) {
const [buttonPressed, setButtonPressed] = useState(false);

const handleSubmit = async () => {
const response = await fetch('/api/main-button', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
type: 'main_build',
leadId: generateLeadId(),
data: payload.registerData
})
});
if (response.ok) {
alert('Запись на обслуживание успешна!');
}
};

const generateLeadId = () => {
// 7 байт → 14 символов hex → lead_id=
const raw = randomBytes(7).toString('hex');
// Сохраняем в БД как составной идентификатор
saveToDatabase(`lead:${raw}-${payload.userId}`, {
leadId: raw,
createdAt: new Date()
});
return raw;
};

return (
<button
onClick={handleSubmit}
disabled={!buttonPressed}
title="Записаться на услуги"
>
{buttonPressed ? '✓ Записался' : '🔠 Записаться'}
</button>
);
}
\n/* Композиционный компонент приложения */\n\nexport default function MiniAppContainer() {\n return (\n <div class=\"miniapp-container\" style=\"padding: 20px; background:#f0f2f5;\">\n \<h1>Мини-приложение Telegram</h1>\n \<p>Нажмите кнопку MainButton, чтобы записаться.</p>\n \<MainButtonComponent payload=\{ registerData: { name: \"Ivan\", email: \"ivan@test.com\" } \}\ />\n \</div>\n);\n}

Найкращі практики та типові помилки

  • Завжди парсіть initData через HMAC-SHA-256, а не просто розбирайте text fields — зловмисник може підмінити payload
  • Ліміт callback_data — не перевищуйте 63 байти (64 – максимум для Telegram API)
  • Ідемпотентні jobs на бекенді мають лагодити update_id, а не просто використовувати останній cursor
  • На стороні фронтенду використовуйте generated lead_id через randomBytes(7) + INSERT в БД, а не заглушки з сесії

Застосування цих кроків гарантує безпечну роботу Telegram Mini App на React та позбавляє більшості OWASP-вразливостей, пов'язаних із підробкою отриманого пакета.

Детальніший розбір підключення Webhook та роботи з Retry-After є важливим, але для старту достатньо освоїти принципи валідації та MainButton.

Для продовження вивчення техніки керування запитами дивіться послідовні статті з автоматизації в Telegram.

Підключайте свій проєкт до офіційного сервісу BotCreator для швидкої інтеграції та експериментів з мінідодатком.

Нові статті — у Telegram

Розбираємо, що автоматизувати в бізнесі та як це працює на практиці. Без спаму.