Init Data
In the list of launch parameters, initialization data is located in the tgWebAppData
parameter. It is a set of data mostly related to a specific user who launched the Mini App.
A striking feature of init data is the fact that it can be used as an authentication or authorization factor. For this reason, do not forget about the security of the application and init data specifically.
Retrieving
To extract init data, a developer can use the retrieveLaunchParams
function from @telegram-apps/sdk.
import { retrieveLaunchParams } from '@telegram-apps/sdk';
const { initDataRaw, initData } = retrieveLaunchParams();
Authorization and Authentication
A special feature of initialization data is the ability to be used as a factor for authorization or authentication. The fact is that the data generated by the native Telegram application is signed with the secret key of the Telegram bot, after which the generated signature is placed next to the parameters themselves.
Thus, knowing the secret key of the Telegram bot, the developer has the opportunity to verify the signature of the parameters and make sure that they were indeed issued to the specified user.
Also, the signature verification operation is fast enough and does not require large server resources.
TIP
You can find examples using different programming languages in this article.
Sending to Server
In order to authorize the user on the server, the developer needs to transmit the initialization data that was specified when launching the Mini App. To make life easier for yourself, the developer can transmit them at each request to the server, after which the signature verification is carried out on the server side.
Here is how a developer could send init data to server:
import { retrieveLaunchParams } from '@telegram-apps/sdk';
const { initDataRaw } = retrieveLaunchParams();
fetch('https://example.com/api', {
method: 'POST',
headers: {
Authorization: `tma ${initDataRaw}`
},
});
In turn, the following actions must be performed on the server side:
- Get the value of the
Authorization
header; - Check that the first part of it is equal to
tma
; - Get init data and validate its signature.
If this algorithm is successful, the server part of the application can trust the transmitted init data.
Validating
Init data validation is one of the most important parts in communication between client and server. It's validity guarantees, that init data can be trusted and used in the future code execution.
TIP
To avoid possible problems related to the init data validation process, we recommend utilizing well-established and tested packages:
- For Node: @telegram-apps/init-data-node
- For GoLang: init-data-golang
Using Telegram Bot Token
Init data validation is one of the most important parts in communication between client and server. It's validity guarantees, that init data can be trusted and used in the future code execution.
Knowing that init data is presented as query parameters list, to validate them, developer should follow the steps:
- Iterate over all key-value pairs and create an array of string values in format
{key}={value}
. Keyhash
should be excluded, but memoized. It represents the init data sign and will be used in the final step of the validation process. - Sort the computed array in the alphabetical order.
- Create HMAC-SHA256 using key
WebAppData
and apply it to the Telegram Bot token, that is bound to your Mini App. - Create HMAC-SHA256 using the result of the previous step as a key. Apply it to the pairs array joined with linebreak (
\n
) received in the 2-nd step and present the result as hex symbols sequence. - Compare the
hash
value received in the 1-st step with the result of the 4-th step. - If these values are equal, passed init data can be trusted.
Example
1. Initial Input
- Telegram Bot token: This value is used to sign the init data, and we will need it in the later steps of the validation process.
5768337691:AAH5YkoiEuPk8-FZa32hStHTqXiLPtAEhx8
- Init data: This data should be passed directly from the mini application to the server as-is.
query_id=AAHdF6IQAAAAAN0XohDhrOrc&user=%7B%22id%22%3A279058397%2C%22first_name%22%3A%22Vladislav%22%2C%22last_name%22%3A%22Kibenko%22%2C%22username%22%3A%22vdkfrost%22%2C%22language_code%22%3A%22ru%22%2C%22is_premium%22%3Atrue%7D&auth_date=1662771648&hash=c501b71e775f74ce10e377dea85a7ea24ecd640b223ea86dfe453e0eaed2e2b2
2. Create Key-Value Pairs and Extract Signature
As per the validation process, we should parse the init data as query parameters. Then, take all key-value pairs excluding the hash
key, join them with the =
symbol, and sort them in alphabetical order. The final array must be joined with the linebreak symbol (\n
).
The result will be:
auth_date=1662771648\nquery_id=AAHdF6IQAAAAAN0XohDhrOrc\nuser={"id":279058397,"first_name":"Vladislav","last_name":"Kibenko","username":"vdkfrost","language_code":"ru","is_premium":true}
The signature is the value in the hash
key. In this case, it equals:
c501b71e775f74ce10e377dea85a7ea24ecd640b223ea86dfe453e0eaed2e2b2
3. Create Telegram Bot Token Signature
To verify if the init data is signed correctly, we need to sign it ourselves. First, we must create an HMAC-SHA256 signature of the Telegram Bot token, using the WebAppData
value as the cryptographic key.
Here is the result:
HMAC-SHA256(
5768337691:AAH5YkoiEuPk8-FZa32hStHTqXiLPtAEhx8,
WebAppData
) = a5c609aa52f63cb5e6d8ceb6e4138726ea82bbc36bb786d64482d445ea38ee5f
WARNING
The received value must not be transformed into a hexadecimal sequence, as shown above. In the next step, use it as-is (an array of bytes), but you can use the hexadecimal value to check if your code generates the hash correctly.
4. Create and Compare Init Data Signature
Finally, we compute the init data signature.
To do this, create another HMAC-SHA256 signature using the transformed init data from Step 2 as the input, and the hash we received in Step 3 as the cryptographic key.
Here is the result:
HMAC-SHA256(
auth_date=1662771648\nquery_id=AAHdF6IQAAAAAN0XohDhrOrc\nuser={"id":279058397,"first_name":"Vladislav","last_name":"Kibenko","username":"vdkfrost","language_code":"ru","is_premium":true},
*signature from Step 3*,
) = c501b71e775f74ce10e377dea85a7ea24ecd640b223ea86dfe453e0eaed2e2b2
Now, by comparing the result with the hash
value from Step 2, we can confirm that they are identical. This means we can trust the passed init data.
Using Telegram Public Key
Another useful feature Telegram provides is it allows validating init data without knowing the bot secret token, but its identifier.
At the moment, there are 2 Ed25519 public keys Telegram provides:
- For production environment:
e7bf03a2fa4602af4580703d88dda5bb59f32ed8b02a56c187fe7d34caed242d
- For test environment:
40055058a4ee38156a06562e52eece92a771bcd8346a8c4615cb7376eddf72ec
To perform this kind of validation (called third-party validation), follow these steps:
- Iterate over all key-value pairs and create an array of string values in format
{key}={value}
. Keyhash
should be excluded. Thesignature
key should also be excluded, but memoized. It represents the init data sign and will be used in the final step of the validation process. - Sort the computed array in the alphabetical order.
- Concatenate Telegram Bot identifier issued the init data with the
WebAppData
string using the semicolon (:
) and append a linebreak (\n
). - Join the pairs from the 2-nd step with the linebreak (
\n
) and append the final value to the value from the 3-rd step. - Verify Ed25519 signature using the value from the
signature
init data key. - If verification is successful, the init data can be trusted.
Example
1. Initial Input
- Production environment: We are validating init data in the production environment. So, this Ed25519 public key will be used:
e7bf03a2fa4602af4580703d88dda5bb59f32ed8b02a56c187fe7d34caed242d
- Init data: This data should be passed directly from the mini application to the server as-is.
user=%7B%22id%22%3A279058397%2C%22first_name%22%3A%22Vladislav%20%2B%20-%20%3F%20%5C%2F%22%2C%22last_name%22%3A%22Kibenko%22%2C%22username%22%3A%22vdkfrost%22%2C%22language_code%22%3A%22ru%22%2C%22is_premium%22%3Atrue%2C%22allows_write_to_pm%22%3Atrue%2C%22photo_url%22%3A%22https%3A%5C%2F%5C%2Ft.me%5C%2Fi%5C%2Fuserpic%5C%2F320%5C%2F4FPEE4tmP3ATHa57u6MqTDih13LTOiMoKoLDRG4PnSA.svg%22%7D&chat_instance=8134722200314281151&chat_type=private&auth_date=1733584787&hash=2174df5b000556d044f3f020384e879c8efcab55ddea2ced4eb752e93e7080d6&signature=zL-ucjNyREiHDE8aihFwpfR9aggP2xiAo3NSpfe-p7IbCisNlDKlo7Kb6G4D0Ao2mBrSgEk4maLSdv6MLIlADQ
2. Create Key-Value Pairs and Extract Signature
As per the validation process, we should parse the init data as query parameters. Then, take all key-value pairs excluding the hash
and signature
keys, join them with the =
symbol, and sort them in alphabetical order. The final array must be joined with the linebreak symbol (\n
).
The result will be:
auth_date=1733584787\nchat_instance=8134722200314281151\nchat_type=private\nuser={"id":279058397,"first_name":"Vladislav + - ? \/","last_name":"Kibenko","username":"vdkfrost","language_code":"ru","is_premium":true,"allows_write_to_pm":true,"photo_url":"https:\/\/t.me\/i\/userpic\/320\/4FPEE4tmP3ATHa57u6MqTDih13LTOiMoKoLDRG4PnSA.svg"}
The signature is the value in the signature
key. In this case, it equals:
zL-ucjNyREiHDE8aihFwpfR9aggP2xiAo3NSpfe-p7IbCisNlDKlo7Kb6G4D0Ao2mBrSgEk4maLSdv6MLIlADQ
Nevertheless, in the future steps, we should convert it to a bytes array, assuming that this value is base64-encoded.
DANGER
At the moment, Telegram sends an invalid signature. Some programming languages (e.g., Go) consider the signature as an invalid base64 value, as long as it doesn't fully comply with the standard. When using the signature, remember to add paddings (=
signs) at the end of the value in case they are needed. In this example, the proper value would be:
zL-ucjNyREiHDE8aihFwpfR9aggP2xiAo3NSpfe-p7IbCisNlDKlo7Kb6G4D0Ao2mBrSgEk4maLSdv6MLIlADQ==
3. Create Data-Check String
Now, let's create a data-check string. To do so, we should join the Telegram Bot token with the WebAppData
string using the semicolon (:
) and append a linebreak. Then, the sorted init data from the previous step should be appended.
Here is the result:
7342037359:WebAppData\nauth_date=1733584787\nchat_instance=8134722200314281151\nchat_type=private\nuser={"id":279058397,"first_name":"Vladislav + - ? \/","last_name":"Kibenko","username":"vdkfrost","language_code":"ru","is_premium":true,"allows_write_to_pm":true,"photo_url":"https:\/\/t.me\/i\/userpic\/320\/4FPEE4tmP3ATHa57u6MqTDih13LTOiMoKoLDRG4PnSA.svg"}
4. Verify Ed25519 Signature
Finally, we verify the signature.
As long as we are in the production environment, we will use the corresponding Ed25519 public key:
e7bf03a2fa4602af4580703d88dda5bb59f32ed8b02a56c187fe7d34caed242d
This value must be converted to a bytes array, assuming that the value is a hexadecimal sequence.
So here is the result of verification:
Ed25519-Verify(
7342037359:WebAppData\nauth_date=1733584787\nchat_instance=8134722200314281151\nchat_type=private\nuser={"id":279058397,"first_name":"Vladislav + - ? \/","last_name":"Kibenko","username":"vdkfrost","language_code":"ru","is_premium":true,"allows_write_to_pm":true,"photo_url":"https:\/\/t.me\/i\/userpic\/320\/4FPEE4tmP3ATHa57u6MqTDih13LTOiMoKoLDRG4PnSA.svg"},
*public key (as a hexadecimal sequence) converted to bytes array*,
*signature (as a base64-encoded value) converted to bytes array*
) == true
If the verification is successful, the init data can be trusted.
Recommendation
In real-world applications, it is recommended to use additional mechanisms for verifying initialization data. For example, add their expiration date. This check can be implemented using the auth_date
parameter, which is responsible for the date when the parameters were created. This solution will allow in case of theft of initialization data to prevent their constant use by an attacker.
Parameters List
This section provides a complete list of parameters used in initialization data.
Parameter | Type | Description |
---|---|---|
auth_date | number | The date the initialization data was created. Is a number representing a Unix timestamp. |
can_send_after | number | Optional. The number of seconds after which a message can be sent via the method answerWebAppQuery. |
chat | Chat | Optional. An object containing data about the chat where the bot was launched via the attachment menu. Returned for supergroups, channels and group chats – only for Mini Apps launched via the attachment menu. |
chat_type | string | Optional. The type of chat from which the Mini Apps was opened. Values:
|
chat_instance | string | Optional. A global identifier indicating the chat from which the Mini Apps was opened. Returned only for applications opened by direct link. |
hash | string | Initialization data signature. |
query_id | string | Optional. The unique session ID of the Mini App. Used in the process of sending a message via the method answerWebAppQuery. |
receiver | User | Optional. An object containing data about the chat partner of the current user in the chat where the bot was launched via the attachment menu. Returned only for private chats and only for Mini Apps launched via the attachment menu. |
start_param | string | Optional. The value of the startattach or startapp query parameter specified in the link. It is returned only for Mini Apps opened through the attachment menu. |
user | User | Optional. An object containing information about the current user. |
Other Types
Chat
Describes the chat information.
Property | Type | Description |
---|---|---|
id | number | Unique chat ID. |
type | string | Chat type. Values:
|
title | string | Chat title. |
photo_url | string | Optional. Chat photo link. The photo can have .jpeg and .svg formats. It is returned only for Mini Apps opened through the attachments menu. |
username | string | Optional. Chat user login. |
User
Describes information about a user or bot.
Property | Type | Description |
---|---|---|
added_to_attachment_menu | boolean | Optional. True, if this user added the bot to the attachment menu. |
allows_write_to_pm | boolean | Optional. True, if this user allowed the bot to message them. |
is_premium | boolean | Optional. Has the user purchased Telegram Premium. |
first_name | string | Bot or user name. |
id | number | Bot or user ID. |
is_bot | boolean | Optional. Is the user a bot. |
last_name | string | Optional. User's last name. |
language_code | string | Optional. IETF user's language. |
photo_url | string | Optional. Link to the user's or bot's photo. Photos can have formats .jpeg and .svg . It is returned only for Mini Apps opened through the attachment menu. |
username | string | Optional. Login of the bot or user. |