Telegram.WebApp.initData
user=%7B%22id%22%3A491735603%2C%22first_name%22%3A%22%F0%9F%85%BD%F0%9F%85%B0%EF%B8%8F%F0%9F%86%83%F0%9F%86%82%22%2C%22last_name%22%3A%22%22%2C%22username%22%3A%22mtNATS%22%2C%22language_code%22%3A%22ru%22%2C%22allows_write_to_pm%22%3Atrue%7D&chat_instance=-3312718360795391383&chat_type=sender&auth_date=1703053222&hash=05dd0f9552a0f12ea994e3616fccf18b0f4c151269664314d9dfd38202e431c5
const initDataString = Telegram.WebApp.initData;
const serverURL = "/auth.php";
function sendToServer(data) {
const xhr = new XMLHttpRequest();
xhr.open("GET", `${serverURL}?${data}`);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
console.log("Server response:", xhr.responseText);
} else {
console.error("Error:", xhr.status, xhr.statusText);
}
}
};
xhr.send();
}
sendToServer(initDataString);
function checkTelegramAuthorization($auth_data) {
$check_hash = $auth_data['hash'];
$_SESSION['hash'] = $check_hash;
unset($auth_data['hash']);
$data_check_arr = [];
foreach ($auth_data as $key => $value) {
$data_check_arr[] = $key . '=' . $value;
}
sort($data_check_arr);
$data_check_string = implode("\n", $data_check_arr);
$secret_key = hash('sha256', BOT_TOKEN, true);
$hash = hash_hmac('sha256', $data_check_string, $secret_key);
if (strcmp($hash, $check_hash) !== 0) {
throw new Exception('Data is NOT from Telegram');
}
if ((time() - $auth_data['auth_date']) > 86400) {
throw new Exception('Data is outdated');
}
return $auth_data;
}
Data is NOT from Telegram
hash_hmac('sha256', BOT_TOKEN, 'WebAppData', true);
// $input — то, что приходит от телеги строкой
parse_str($input, $initData);
$data = [];
foreach ($initData as $name => $item) {
if ($name === 'hash') continue;
$data[] = $name . '=' . $item;
}
sort($data);
$hashKey = hash_hmac('sha256', BOT_TOKEN, 'WebAppData', true);
$hash = hash_hmac('sha256', implode("\n", $data), $hashKey);
echo $hash !== $initData['hash'] ? 'BAD' : 'OK';
class HasherDataAction
{
const WEB_APP_DATA_CONST = 'WebAppData';
public function handle(string $bot_token, ValidateData $data): string {
$data_check = (array) $data;
ksort($data_check, SORT_NATURAL);
$data_check_string = urldecode(http_build_query($data_check, arg_separator: "\n"));
$secret_key = $this->sha256($bot_token, self::WEB_APP_DATA_CONST);
$hash_data = $this->sha256($data_check_string, $secret_key);
return bin2hex($hash_data);
}
private function sha256(string $data, string $key) {
return hash_hmac('sha256', $data, $key, true);
}
}
namespace WebApp\Domain\Data;
readonly class ValidateData
{
public function __construct(
public string $query_id,
public string $user,
public string $auth_date
) {
}
}
import axios from "axios";
const { initData } = window.Telegram.WebApp
document.addEventListener('DOMContentLoaded', () => {
validateData(initData)
})
function validateData(data) {
// как по мне лучше сразу передать данными и не парcить это в PHP, так проще и можно валидировать.
// axios.post('/{your_controller_validate_date}', data).then(response => {})
// оставлю вариант с передачей строки в initData
axios.post('/{your_controller_validate_date}', {initData: data})
.then(response => { console.log(response.data) })
}
// данные из JS, $_POST['initData']
$initData = 'user=%7B%22id%22%3A491735603%2C%22first_name%22%3A%22%F0%9F%85%BD%F0%9F%85%B0%EF%B8%8F%F0%9F%86%83%F0%9F%86%82%22%2C%22last_name%22%3A%22%22%2C%22username%22%3A%22mtNATS%22%2C%22language_code%22%3A%22ru%22%2C%22allows_write_to_pm%22%3Atrue%7D&chat_instance=-3312718360795391383&chat_type=sender&auth_date=1703053222&hash=05dd0f9552a0f12ea994e3616fccf18b0f4c151269664314d9dfd38202e431c5';
parse_str($initData, $data_array); // если отправляете данными, это не нужно, у вас сразу будет массив с данными в $_POST;
// $data_array = $_POST
$hash = $data_array['hash'];
$data = new ValidateData($data_array['query_id'], $data_array['user'], $data_array['auth_date']);
$data_hash = (new HasherDataAction)->handle('YOUR_BOT_TOKEN', $data);
// true/false
$isValid = $data_hash == $hash;