I am trying to implement Log in with Telegram (https://core.telegram.org/widgets/login) on my Spring Boot application, but faced a problem.
I’ve been trying to implement PHP code they provided to verify authentication, but something is wrong and I can’t understand what.
So, that’s the code on PHP
secret_key = SHA256(<bot_token>)
if (hex(HMAC_SHA256(data_check_string, secret_key)) == hash) {
// data is from Telegram
}
Data-check-string is a concatenation of all received fields, sorted in alphabetical order, in the format key=<value>
with a line feed character (‘n’, 0xA0) used as separator – e.g., 'auth_date=<auth_date>nfirst_name=<first_name>nid=<id>nusername=<username>
.
So, what I did is:
@AllArgsConstructor
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public class AuthenticationRequest {
@NotNull
private Long authDate;
private String firstName;
@NotEmpty
private String id;
private String lastName;
private String photoUrl;
private String username;
@NotEmpty
private String hash;
@Override
public String toString() {
final var data = new StringBuilder();
for (final Field field : getClass().getDeclaredFields()) {
try {
if (!field.getName().equals("hash") && field.get(this) != null) {
final var fieldName = CaseFormat.LOWER_CAMEL
.to(CaseFormat.LOWER_UNDERSCORE, field.getName());
data.append(fieldName).append("=").append(field.get(this)).append("\n");
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return data.substring(0, data.length() - 2);
}
}
And these two methods:
private static String hmacSha256(final String data, final byte[] secret) {
try {
Mac sha256Hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(secret, "HmacSHA256");
sha256Hmac.init(secretKey);
byte[] signedBytes = sha256Hmac.doFinal(data.getBytes());
return bytesToHex(signedBytes);
} catch (NoSuchAlgorithmException | InvalidKeyException ex) {
return null;
}
}
private static String bytesToHex(byte[] hash) {
StringBuilder hexString = new StringBuilder();
for (final byte b : hash) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
return hexString.toString();
}
And when I compare them, they are completely different two strings
final var telegramData = authenticationRequest.toString();
final var digest = MessageDigest.getInstance("SHA-256");
final var hashedToken = digest.digest(botToken.getBytes());
System.out.println(authenticationRequest.getHash());
System.out.println(hmacSha256(telegramData, hashedToken));
Could you please give me a hint on what I am doing wrong? Maybe I completely misunderstood the way I have to validate the authentication data, or maybe I missed something?
2
Answers
try this, the code is kind of ugly, but it worked well!
Here is my implement