# Telegram MiniAPP 開發

## 設置 MiniAPP

1. 在 Telegram 內搜尋 botfather

![](/files/N9ydO2KBFxwS7P7sQE8u)

2. 左下角選單選擇 newbot 創建機器人

<div align="left"><figure><img src="/files/yftpyWnWKuCaDA8vRJRI" alt="" width="188"><figcaption></figcaption></figure></div>

3. 創建好機器人後，一樣到選單，選擇創建 newapp

![](/files/wG3DhUby2wo3apFNggqU)

4. 之後他會要你選擇一個綁定的 bot，選剛才創件的 bot，然後上傳 640x360 pixels 圖片，然後放上 miniApp 部署的 https 網頁 URL (可以先用 ngrok 方便開發)，之後他就會給你 miniAPP url 點擊後會開起 miniApp。

## 開發 MiniApp

我們可以使用模板來創建專案：

{% embed url="<https://github.com/telegram-mini-apps-dev/vite-boilerplate?tab=readme-ov-file>" %}

專案跑起來後，去下載 ngrok <https://ngrok.com/> ，接著就是前面步驟的設置 miniApp URL 為 ngrok 提供的 HTTPS URL (記得要 HTTPS)。

接著就可以參考以下文件進行開發 &#x20;

<https://core.telegram.org/bots/webapps#initializing-mini-apps>

## 驗證用戶

用戶登入 miniApp 時我們可以獲得 initData 裡面包含用戶名稱與 id 等等，當中包含 miniApp 幫用戶自動產生的 hash，而我們要用加密驗證的方式來將 tg bot 與這個 hash 驗證，確定實際上是這個用戶在操作 APP，可使用以下代碼來驗正

前端：

```javascript
  useEffect(() => {
    const webApp = window?.Telegram.WebApp;
    console.log('WebAppInitData:', webApp.initData); // querystring 型態
  }, [window?.Telegram.WebApp]);
```

後端：

```typescript
  async signinUser(webInitData: string, ip: string) {
    function validateTelegramWebAppData(initData, botToken) {
      // Step 1: Parse initData into an object
      const params = new URLSearchParams(initData);
      const dataObj = {};
      params.forEach((value, key) => {
        dataObj[key] = value;
      });
    
      // Step 2: Extract and remove the hash
      const receivedHash = dataObj['hash'];
      delete dataObj['hash'];
    
      // Step 3: Sort the keys and construct dataCheckString
      const dataCheckString = Object.keys(dataObj)
        .sort()
        .map(key => `${key}=${dataObj[key]}`)
        .join('\n');
    
      // Step 4: Create a secret key using the bot token
      const secretKey = createHmac('sha256', 'WebAppData')
        .update(botToken)
        .digest();
    
      // Step 5: Hash the dataCheckString using the secret key
      const calculatedHash = createHmac('sha256', secretKey)
        .update(dataCheckString)
        .digest('hex');
    
      // Step 6: Compare calculated hash with received hash (both should be lowercase)
      return { isOk: calculatedHash === receivedHash, dataObj };
    }
    if (!webInitData) {
      throw new BadRequestException('webInitData is required');
    }
    
    const botToken = process.env['TG_BOT_TOKEN']; // 這邊記得在 .env 檔案放上 TG_BOT_TOKEN 
    
    const { isOk, dataObj } = validateTelegramWebAppData(webInitData, botToken)
    if (!isOk) {
      throw new BadRequestException('Invalid tg sigature');
    }
    const userData = JSON.parse(dataObj['user']);
    
    if (!botToken) {
      console.log('Something wrong for tg bot token');
      throw new BadRequestException('Something wrong for tg bot token');
    }

    const userId = String(userData['id']);
    const username = String(userData['username']);
    // 到了這邊已經驗證用戶成功，可以使用 userData 內的資料來進行操作
  }
```

{% embed url="<https://core.telegram.org/bots/webapps#validating-data-received-via-the-mini-app>" %}

## 其他工具

手機端開發時的 console.log 工具 <https://github.com/liriliri/eruda>

> 會在右下角有按鈕，打開可以看到 log


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://easonwang.gitbook.io/web_advance/telegram-miniapp-kai-fa.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
