Search code examples
c#.nettelegram

C# check telegram login hmac


I've tried to implement telegram login widget on my project but faced with problem. I don't know why, but hash that I received from telegram and hash that I calculated (by tutorial from telegram) doesn't equal. I wrote my own hash calculating method, and tried to use telegram login widget nuget package but both ways doesn't work :(.

My hash calculating methods:

public class TelegramHmacTest
{
    private const string BotToken = "123:ABC";
    private const string ExpectedHash = "blablabla";
    
    [Fact]
    public void HmacTest()
    {
        var info = new Dictionary<string, string>
        {
            {"auth_date", "1234567"},
            {"first_name", "abc"},
            {"id", "123456"},
            {"photo_url", "https://t.me/i/userpic/...jpg"},
            {"username", "usr"},
        };

        var dataString = CombineString(info);
        var computedHash = HashHMAC(dataString);

        Assert.Equal(ExpectedHash, computedHash.ToLower());
    }

    private string HashHMAC(string message)
    {
        using var hasher = SHA256.Create();
        var keyBytes = hasher.ComputeHash(Encoding.UTF8.GetBytes(BotToken));

        var messageBytes = Encoding.UTF8.GetBytes(message);
        var hash = new HMACSHA256(keyBytes);
        var computedHash = hash.ComputeHash(messageBytes);
        return Convert.ToHexString(computedHash);
    }

    private string CombineString(IReadOnlyDictionary<string, string> meta)
    {
        var builder = new StringBuilder();

        TryAppend("auth_date");
        TryAppend("first_name");
        TryAppend("id");
        TryAppend("last_name");
        TryAppend("photo_url");
        TryAppend("username", true);

        return builder.ToString();

        void TryAppend(string key, bool isLast = false)
        {
            if (meta.ContainsKey(key))
                builder.Append($"{key}={meta[key]}{(isLast ? "" : "\n")}");
        }
    }
}

Calculating hash using library:

[Fact]
    public void TestLib()
    {
        var BotToken = "123:ABC";
        var info = new Dictionary<string, string>
        {
            {"auth_date", "1234567"},
            {"first_name", "abc"},
            {"id", "123456"},
            {"photo_url", "https://t.me/i/userpic/...jpg"},
            {"username", "usr"},
        };

        var loginWidget = new LoginWidget(BotToken);
        if (loginWidget.CheckAuthorization(info) == Authorization.Valid)
        {
            // user valid
        }
    }

Maybe someone had a similar problem?


Solution

  • The problem was in I've not registered domain in BotFather. In Telegram Login Widget documentation there is no information about you have to register your domain for your bot in BotFather. Also I've discovered that you can register only https domains and '127.0.0.1' for testing.