Skip to content

Instantly share code, notes, and snippets.

@immmdreza
Last active April 21, 2026 19:12
Show Gist options
  • Select an option

  • Save immmdreza/29415b29106d759371fbab23b67fff20 to your computer and use it in GitHub Desktop.

Select an option

Save immmdreza/29415b29106d759371fbab23b67fff20 to your computer and use it in GitHub Desktop.
// Parse string initData from telegram.
var data = HttpUtility.ParseQueryString(initData);
// Put data in a alphabetically sorted dict.
var dataDict = new SortedDictionary<string, string>(
data.AllKeys.ToDictionary(x => x!, x => data[x]!),
StringComparer.Ordinal);
// Constant key to genrate secret key.
var constantKey = "WebAppData";
// https://core.telegram.org/bots/webapps#validating-data-received-via-the-web-app:
// Data-check-string is a chain of all received fields,
// sorted alphabetically.
// in the format key=<value>.
// with a line feed character ('\n', 0x0A) used as separator.
// e.g., 'auth_date=<auth_date>\nquery_id=<query_id>\nuser=<user>'
var dataCheckString = string.Join(
'\n', dataDict.Where(x => x.Key != "hash") // Hash should be removed.
.Select(x => $"{x.Key}={x.Value}")); // like auth_date=<auth_date> ..
// You may replace line above with line below specially in Asp .Net Core.
//
// .Select(x => $"{x.Key}={HttpUtility.UrlDecode(x.Value)}"));
// secrecKey is the HMAC-SHA-256 signature of the bot's token
// with the constant string WebAppData used as a key.
var secretKey = HMACSHA256.HashData(
Encoding.UTF8.GetBytes(constantKey), // WebAppData
Encoding.UTF8.GetBytes(_botConfig.BotToken)); // Bot's token
var generatedHash = HMACSHA256.HashData(
secretKey,
Encoding.UTF8.GetBytes(dataCheckString)); // data_check_string
// Convert received hash from telegram to a byte array.
var actualHash = Convert.FromHexString(dataDict["hash"]); // .NET 5.0
// Compare our hash with the one from telegram.
if (actualHash.SequenceEqual(generatedHash))
{
// Data from telegram.
}
@ZnZq

ZnZq commented Jan 25, 2023

Copy link
Copy Markdown

For .NET Core 3
You can use byte[] HmacSHA256(byte[] code, byte[] data) { using (HMACSHA256 hmac = new HMACSHA256(code)) { var hmBytes = hmac.ComputeHash(data); return hmBytes; } } instead of HMACSHA256.HashData

@Gridiron

Gridiron commented Jan 26, 2023

Copy link
Copy Markdown

There is no way this code can work because you use HMACSHA256 for hashing of token for secret key instead of SHA256.

@immmdreza

immmdreza commented Jan 26, 2023

Copy link
Copy Markdown
Author

There is no way this code can work because you use HMACSHA256 for hashing of token for secret key instead of SHA256.

data_check_string = ...
secret_key = HMAC_SHA256(<bot_token>, "WebAppData")
if (hex(HMAC_SHA256(data_check_string, secret_key)) == hash) {
  // data is from Telegram
}

Telegram docs noticed that it should be HMAC_SHA256.

Iโ€™m not really sure that itโ€™s working at the moment, but it was.

@Polaroid15

Copy link
Copy Markdown

@immmdreza Man! Thank you very much!

@immmdreza

Copy link
Copy Markdown
Author

@immmdreza Man! Thank you very much!
๐Ÿ™

@nyatt9992

Copy link
Copy Markdown

data_check_string = ...
secret_key = SHA256(<bot_token>)
if (hex(HMAC_SHA256(data_check_string, secret_key)) == hash) {
// data is from Telegram
}

@stylophone

stylophone commented Jul 15, 2024

Copy link
Copy Markdown

Thanks for the code!

@layinka

layinka commented Sep 27, 2024

Copy link
Copy Markdown

Thanks, This really helped

@romanov

romanov commented Oct 30, 2025

Copy link
Copy Markdown

The ?user= part of initData (miniapp) is a json (in asp.net core), so u need

var dataCheckString = string.Join(
            '\n', dataDict.Where(x => x.Key != "hash") // Hash should be removed.
                .Select(x => $"{x.Key}={HttpUtility.UrlDecode(x.Value)}"));```

@MrVeit

MrVeit commented Dec 13, 2025

Copy link
Copy Markdown

The ?user= part of initData (miniapp) is a json (in asp.net core), so u need

var dataCheckString = string.Join(
            '\n', dataDict.Where(x => x.Key != "hash") // Hash should be removed.
                .Select(x => $"{x.Key}={HttpUtility.UrlDecode(x.Value)}"));```

Yeah, this algorithm works as intended with this fix on ASP.NET Core. Thank you to everyone who helped! :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment