Разработка Telegram Mini App на React требует особого подхода к инициализации WebApp и строгой vалидации 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 для быстрой интеграции и экспериментов с мини-приложением.