Изначально значение представленно в виде URl параметров

1. Спарсим initData в объект.

typescript
const params: Record<string, string> = {}
const pairs = initData.split('&')
  
for (const pair of pairs) {
  const [key, value] = pair.split('=')
  params[key] = value
}
Результат выполнения
{}

2. Удаляем ключ hash из объекта

Прежде сохраняем его значение в переменной!

3. Отсортируем объект по ключам в алфавитном порядке.

typescript
const sortedParams: Record<string, string> = {}
Object.keys(params)
.sort()
.forEach((key) => {
  sortedParams[key] = params[key];
});
Результат выполнения
{}

4. Преобразуем отсортированный объект в строку вида - "key1=value1\nkey2=value2\n..."

typescript
const dataCheckString = Object.entries(sortedParams)
  .map(([key, value]) => `${key}=${value}`)
  .join("
")
Результат выполнения

5. Создадим секретный ключ. Хешируем токен бота по ключу "WebAppData" алгоритмом hmacSHA256.

typescript
const secretKey = hmacSHA256(botToken, "WebAppData")
Результат выполнения

6. Создаём хеш значения dataCheckString по ключу secretKey алгоритмом hmacSHA256 и преобразуем в строку.

typescript
const computedHash = hmacSHA256(dataCheckString, secretKey).toString(Hex)
Результат выполнения
""

7. Сравниваем полученный хеш с хешем из параметров initData