I try to rewrite validation code to JS + cryptoJS:
var secret_key = CryptoJS.HmacSHA256(bot.token, "WebAppData");
var key = CryptoJS.HmacSHA256(initData, secret_key)
// initData it is - Telegram.WebApp.initData
if(key==hash){
// validated
}
// I have also tried converting 'key' to hex:
key = key.toString(CryptoJS.enc.Hex);
key == hash // always false too
But my validation is always false.
What fixes are needed?
3
Answers
Solution
This is a ported version of the Python solution found in
Aiogram
Here is a Sandbox
Clarifying the documentation
Honestly, the documentation is quite twisted and can be improved. But there are some hints to what may be going on.
1) Format
So
initData
is a URL Queryname=One&surname=Two
where the expecteddata_check_string
should be new line separatedname=Onensurname=Two
2) Hash is included
This is not explicated in the documentation, but
initData
includes thehash
in the formname=One&surname=Two&...&hash=...
. Being almost impossible to include the hash of the document in the document itself hints at the fact that the stringinitData
is not the one being hashed. InAiogram
you find a confirmation of this.You need to exclude hash parameter from
initData
before computing hash for comparison and order other parameters in alphabetical order. Also you do need to convert key(computed hash to hex), cause hash present in initData from telegram is in hex format.Maybe this is not exactly what you need, but you can still check initData in PHP. Here I found a great solution TgWebValid