diff --git a/src/pages/guides/telegram-miniapp-client.mdx b/src/pages/guides/telegram-miniapp-client.mdx index 1439fa15f..bff27879b 100644 --- a/src/pages/guides/telegram-miniapp-client.mdx +++ b/src/pages/guides/telegram-miniapp-client.mdx @@ -2,9 +2,9 @@ title: "Client-Side Setup for Telegram Mini App with Web3Auth" image: "guides-banners/telegram-miniapp-client.png" description: | - Learn how to set up the client-side of a Telegram Mini App using Web3Auth to authenticate users and retrieve wallet details. This guide is the second part of the Telegram Mini App series. + Learn how to set up the client-side of a Telegram Mini App using Web3Auth Web SDK to authenticate users and retrieve wallet details. This guide is the second part of the Telegram Mini App series. type: guide -tags: [client, telegram, authentication, web3auth, ton] +tags: [client, telegram, authentication, web3auth, ton, web-sdk] date: October 24, 2024 author: Web3Auth Team --- @@ -14,7 +14,7 @@ import TelegramMiniAppDiagram from "@site/static/images/telegram-mini-app-flow-d @@ -30,19 +30,20 @@ Before diving into development, experience Web3Auth in action! Check out our dem :::info Source Code You can find the full working code for this client + server example here: -[**Web3Auth Telegram Mini App Example**](https://github.com/Web3Auth/web3auth-core-kit-examples/tree/main/single-factor-auth-web/sfa-web-ton-telegram-example) +[**Web3Auth Telegram Mini App Example**](https://github.com/Web3Auth/web3auth-pnp-examples/tree/main/other/ton-telegram-example) ::: ### **Objectives** -In this guide, we will focus on setting up the client-side of a Telegram Mini App using Web3Auth for -authentication. By the end of this guide, you will: +In this guide, we will focus on setting up the client-side of a Telegram Mini App using Web3Auth Web +SDK for authentication. By the end of this guide, you will: -1. Implement Web3Auth in the **client-side app** to authenticate Telegram users using the JWT tokens - generated in [Part 1](/guides/telegram-miniapp-server). +1. Implement Web3Auth Web SDK in the **client-side app** to authenticate Telegram users using the + JWT tokens generated in [Part 1](/guides/telegram-miniapp-server). 2. Retrieve wallet details (e.g., TON blockchain addresses) via Web3Auth and display them in the app. +3. Create a seamless user experience with automatic authentication flow. :::tip @@ -57,16 +58,16 @@ before proceeding with this guide. ### **Guide Breakdown** 1. **Part 1**: Set up the server-side logic to validate Telegram login data and generate JWT tokens. -2. **Part 2 (Current Guide)**: Focuses on integrating Web3Auth into the client-side app to +2. **Part 2 (Current Guide)**: Focuses on integrating Web3Auth Web SDK into the client-side app to authenticate users and retrieve their wallet details. --- ### Overview -In this guide, we will implement the client-side part of the Telegram Mini App. The client will -handle user interaction, manage the login flow using Web3Auth, and retrieve wallet details from the -TON blockchain. +In this guide, we will implement the client-side part of the Telegram Mini App using Web3Auth Web +SDK. The client will handle user interaction, manage the login flow using Web3Auth's Web SDK, and +retrieve wallet details from the TON blockchain. We'll be using the JWT token generated in [Part 1](/guides/telegram-miniapp-server) of this guide to authenticate users on the client-side and establish a session with Web3Auth to retrieve @@ -81,18 +82,19 @@ The flow is as follows: /> 1. The user logs into the Telegram Mini App. -2. The JWT token (generated from the backend) is passed to Web3Auth for authentication. -3. Web3Auth authenticates the user and retrieves wallet details (e.g., the user's TON blockchain - address). +2. The JWT token (generated from the backend) is passed to Web3Auth Web SDK for authentication. +3. Web3Auth Web SDK authenticates the user and retrieves wallet details (e.g., the user's TON + blockchain address). 4. The client displays the wallet details to the user. --- ### **What You Will Learn:** -1. Integrate Web3Auth into a client-side app to handle user authentication. +1. Integrate Web3Auth Web SDK into a client-side app to handle user authentication. 2. Retrieve wallet details (TON blockchain) from Web3Auth. 3. Mock Telegram environments for local development and testing. +4. Create a modern, responsive UI for the Telegram Mini App. --- @@ -105,20 +107,21 @@ The flow is as follows: Before starting, install the required dependencies for the client-side app. ```bash -npm install @web3auth/single-factor-auth @telegram-apps/sdk-react dotenv @orbs-network/ton-access +npm install @web3auth/modal @telegram-apps/sdk-react tonweb @orbs-network/ton-access lucide-react ``` #### **Brief Overview of Dependencies:** -- **@web3auth/single-factor-auth**: This is the core package for using Web3Auth's Single Factor - Authentication (SFA) flow, which will allow us to authenticate Telegram users and retrieve - blockchain data. +- **@web3auth/modal**: This is the core package for using Web3Auth's Web SDK, which provides a + seamless authentication experience with a built-in UI modal for user login. - **@telegram-apps/sdk-react**: This package is used to handle Telegram's launch parameters and mock Telegram environments for testing during development. -- **dotenv**: Allows loading environment variables from a `.env` file, ensuring secure storage of - sensitive data such as server URLs. +- **tonweb**: A JavaScript library for interacting with the TON blockchain, enabling wallet + operations and transaction signing. - **@orbs-network/ton-access**: Provides access to the TON blockchain RPC endpoint for fetching account information and signing messages on the TON network. +- **lucide-react**: A beautiful icon library for React applications, used for UI elements like copy + buttons and theme toggles. --- @@ -143,86 +146,70 @@ the states that will manage the login flow, user data, and TON blockchain intera ```tsx import { useEffect, useState } from "react"; -import { Web3Auth, decodeToken } from "@web3auth/single-factor-auth"; -import { CHAIN_NAMESPACES, WEB3AUTH_NETWORK } from "@web3auth/base"; -import { CommonPrivateKeyProvider } from "@web3auth/base-provider"; +import { + Web3Auth, + WEB3AUTH_NETWORK, + WALLET_CONNECTORS, + AUTH_CONNECTION, +} from "@web3auth/modal"; +import TonRPC from "./tonRpc"; import { useLaunchParams } from "@telegram-apps/sdk-react"; import { useTelegramMock } from "./hooks/useMockTelegramInitData"; -import { getHttpEndpoint } from "@orbs-network/ton-access"; +import { Sun, Moon, Copy, Check } from "lucide-react"; +import Loading from "./components/Loading"; import "./App.css"; -const verifier = "w3a-telegram-demo"; +const authConnectionId = "w3a-telegram-demo"; const clientId = "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ"; function App() { const [isLoggingIn, setIsLoggingIn] = useState(false); - const [web3authSfa, setWeb3authSfa] = useState(null); + const [web3Auth, setWeb3Auth] = useState(null); const [web3AuthInitialized, setWeb3AuthInitialized] = useState(false); const [userData, setUserData] = useState(null); const [tonAccountAddress, setTonAccountAddress] = useState(null); const [signedMessage, setSignedMessage] = useState(null); const [isLoggedIn, setIsLoggedIn] = useState(false); + const [isDarkMode, setIsDarkMode] = useState(false); + const [copiedStates, setCopiedStates] = useState<{ [key: string]: boolean }>({ + account: false, + message: false, + }); - const { initDataRaw, initData, themeParams } = useLaunchParams() || {}; + const { initDataRaw, initData } = useLaunchParams() || {}; useTelegramMock(); // Initialize the Telegram mock data ``` - **Explanation**: In this step, we import the necessary libraries and set up states like - `isLoggingIn`, `web3authSfa`, `web3AuthInitialized`, `userData`, `tonAccountAddress`, and - `signedMessage` that will manage our app's flow. + `isLoggingIn`, `web3Auth`, `web3AuthInitialized`, `userData`, `tonAccountAddress`, and + `signedMessage` that will manage our app's flow. The Web3Auth Web SDK provides a streamlined + approach for authentication and blockchain interactions. --- -### Step 4: Initialize Web3Auth and Fetch the ID Token +### Step 4: Initialize Web3Auth Web SDK -Now that the states are set up, let's move on to initializing **Web3Auth** and setting up the -connection to our backend server to fetch the ID token generated in +Now that the states are set up, let's move on to initializing **Web3Auth Web SDK** and setting up +the connection to our backend server to fetch the ID token generated in **[Part 1](/guides/telegram-miniapp-server)**. -#### Web3Auth Initialization and Configuration +#### Web3Auth Web SDK Initialization and Configuration ```tsx useEffect(() => { const initializeWeb3Auth = async () => { try { - console.log("Fetching TON Testnet RPC endpoint..."); - const testnetRpc = await getHttpEndpoint({ - network: "testnet", - protocol: "json-rpc", - }); - - const chainConfig = { - chainNamespace: CHAIN_NAMESPACES.OTHER, - chainId: "testnet", - rpcTarget: testnetRpc, - displayName: "TON Testnet", - blockExplorerUrl: "https://testnet.tonscan.org", - ticker: "TON", - tickerName: "Toncoin", - }; - - const privateKeyProvider = new CommonPrivateKeyProvider({ - config: { chainConfig }, - }); - - // Initialize Web3Auth const web3authInstance = new Web3Auth({ clientId, web3AuthNetwork: WEB3AUTH_NETWORK.SAPPHIRE_MAINNET, - usePnPKey: false, - privateKeyProvider, }); - setWeb3authSfa(web3authInstance); - - console.log("Initializing Web3Auth..."); + setWeb3Auth(web3authInstance); await web3authInstance.init(); - console.log("Web3Auth initialized."); - setWeb3AuthInitialized(true); } catch (error) { - console.error("Error fetching TON Testnet RPC endpoint: ", error); + console.error("Error initializing Web3Auth:", error); } }; @@ -230,9 +217,9 @@ useEffect(() => { }, []); ``` -- **Explanation**: This block initializes Web3Auth using the **Single Factor Authentication** - method. We also fetch the TON blockchain's testnet RPC endpoint, which will allow us to connect to - the network and retrieve blockchain data such as the wallet address. +- **Explanation**: This block initializes Web3Auth using the **Web SDK**. The Web SDK provides a + simplified initialization process, automatically handling chain configurations and provider setup. + The Web SDK is designed to work seamlessly with various blockchain networks, including TON. --- @@ -248,9 +235,7 @@ development. We achieve this by using the `useTelegramMock()` hook. import { mockTelegramEnv, parseInitData, retrieveLaunchParams } from "@telegram-apps/sdk-react"; /** - * Mocks - - Telegram environment in development mode. + * Mocks Telegram environment in development mode. */ export function useTelegramMock(): void { if (process.env.NODE_ENV !== "development") return; @@ -327,40 +312,43 @@ Telegram SDK might throw errors or behave unexpectedly when not running within T --- -### Step 6: Connecting to Web3Auth and Fetching the ID Token +### Step 6: Connecting to Web3Auth Web SDK and Fetching the ID Token -Now, let's connect to Web3Auth and retrieve the ID token from our backend server, as configured in -**[Part 1](/guides/telegram-miniapp-server)**. +Now, let's connect to Web3Auth Web SDK and retrieve the ID token from our backend server, as +configured in **[Part 1](/guides/telegram-miniapp-server)**. -#### Connecting Web3Auth +#### Connecting Web3Auth Web SDK ```tsx useEffect(() => { const connectWeb3Auth = async () => { - if (web3authSfa && web3AuthInitialized && initDataRaw) { + if (web3Auth && web3AuthInitialized && initDataRaw) { setIsLoggingIn(true); try { - if (web3authSfa.status === "connected") { - await web3authSfa.logout(); + if (web3Auth.status === "connected") { + await web3Auth.logout(); } - const idToken = await getIdTokenFromServer(initDataRaw, initData.user.photoUrl); // Fetch ID token - const { payload } = decodeToken(idToken); + const idToken = await getIdTokenFromServer(initDataRaw, initData?.user.photoUrl); + if (!idToken) return; - await web3authSfa.connect({ - verifier, - verifierId: payload.sub, + await web3Auth.connectTo(WALLET_CONNECTORS.AUTH, { + authConnectionId, + authConnection: AUTH_CONNECTION.CUSTOM, idToken, + extraLoginOptions: { + isUserIdCaseSensitive: true, + }, }); - setUserData(payload); setIsLoggedIn(true); - const tonRpc = new TonRPC(web3authSfa.provider); + const tonRpc = new TonRPC(web3Auth.provider); const tonAddress = await tonRpc.getAccounts(); setTonAccountAddress(tonAddress); - const signedMsg = await tonRpc.signMessage("Hello, TON!"); + const messageToSign = "Hello, TON!"; + const signedMsg = await tonRpc.signMessage(messageToSign); setSignedMessage(signedMsg); } catch (error) { console.error("Error during Web3Auth connection:", error); @@ -373,73 +361,248 @@ useEffect(() => { if (web3AuthInitialized && initDataRaw) { connectWeb3Auth(); } -}, [initDataRaw, web3authSfa, web3AuthInitialized]); +}, [initDataRaw, web3Auth, web3AuthInitialized, initData?.user.photoUrl]); + +useEffect(() => { + if (initData?.user) { + setUserData(initData.user); + } +}, [initData]); + +const getIdTokenFromServer = async (initDataRaw: string, photoUrl: string | undefined) => { + const isMocked = !!sessionStorage.getItem("____mocked"); + const response = await fetch(`${import.meta.env.VITE_SERVER_URL}/auth/telegram`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ initDataRaw, isMocked, photoUrl }), + }); + const data = await response.json(); + return data.token; +}; ``` -- **Explanation**: This effect establishes a connection to Web3Auth using the ID token fetched from - the backend. Once connected, we fetch the TON blockchain account details, including the account - address and a signed message. +- **Explanation**: This effect establishes a connection to Web3Auth Web SDK using the ID token + fetched from the backend. The Web SDK's `connectTo` method with `WALLET_CONNECTORS.AUTH` provides + a streamlined way to authenticate users with custom JWT tokens. Once connected, we fetch the TON + blockchain account details, including the account address and a signed message. --- -### Step 7: Display User and TON Account Information +### Step 7: Create TON RPC Class for Blockchain Interactions -Finally, we display the user's Telegram profile details and their TON account address along with the -signed message. +Create a `tonRpc.ts` file to handle TON blockchain interactions: ```tsx -const userInfoBox = ( -
- User avatar -
-

- ID: {userData?.telegram_id} -

-

- Username: {userData?.username} -

-

- Name: {userData?.name} -

-
-
-); +import type { IProvider } from "@web3auth/modal"; +import { getHttpEndpoint } from "@orbs-network/ton-access"; +import TonWeb from "tonweb"; -const tonAccountBox = ( -
-

- TON Account: {tonAccountAddress} -

-
-); +const rpc = await getHttpEndpoint(); -const signedMessageBox = ( -
-

- Signed Message: {signedMessage} -

-
-); +export default class TonRPC { + private provider: IProvider; + private tonweb: TonWeb; + + constructor(provider: IProvider) { + this.provider = provider; + this.tonweb = new TonWeb(new TonWeb.HttpProvider(rpc)); + } + + async getAccounts(): Promise { + try { + const privateKey = await this.getPrivateKey(); + const keyPair = this.getKeyPairFromPrivateKey(privateKey); + const WalletClass = this.tonweb.wallet.all["v3R2"]; + const wallet = new WalletClass(this.tonweb.provider, { + publicKey: keyPair.publicKey, + }); + const address = await wallet.getAddress(); + return address.toString(true, true, true); + } catch (error) { + console.error("Error getting accounts:", error); + return ""; + } + } + + async signMessage(message: string): Promise { + try { + const privateKey = await this.getPrivateKey(); + const keyPair = this.getKeyPairFromPrivateKey(privateKey); + + const messageBytes = new TextEncoder().encode(message); + const signature = TonWeb.utils.nacl.sign.detached(messageBytes, keyPair.secretKey); + + return Buffer.from(signature).toString("hex"); + } catch (error) { + console.error("Error signing message:", error); + throw error; + } + } + + private getKeyPairFromPrivateKey(privateKey: string): { + publicKey: Uint8Array; + secretKey: Uint8Array; + } { + const privateKeyBytes = new Uint8Array( + privateKey.match(/.{1,2}/g)!.map((byte) => parseInt(byte, 16)), + ); + + if (privateKeyBytes.length !== 32) { + const adjustedPrivateKey = new Uint8Array(32); + adjustedPrivateKey.set(privateKeyBytes.slice(0, 32)); + return TonWeb.utils.nacl.sign.keyPair.fromSeed(adjustedPrivateKey); + } + + return TonWeb.utils.nacl.sign.keyPair.fromSeed(privateKeyBytes); + } + + private async getPrivateKey(): Promise { + try { + return await this.provider.request({ + method: "private_key", + }); + } catch (error) { + console.error("Error getting private key:", error); + throw error; + } + } +} +``` + +--- + +### Step 8: Display User and TON Account Information + +Finally, we display the user's Telegram profile details and their TON account address along with the +signed message in a modern, responsive UI: + +```tsx +const copyToClipboard = async (text: string, type: "account" | "message") => { + try { + await navigator.clipboard.writeText(text); + setCopiedStates((prev) => ({ + ...prev, + [type]: true, + })); + + // Reset the copied state after 2 seconds + setTimeout(() => { + setCopiedStates((prev) => ({ + ...prev, + [type]: false, + })); + }, 2000); + } catch (err) { + console.error("Failed to copy text:", err); + } +}; + +const toggleDarkMode = () => { + setIsDarkMode(!isDarkMode); +}; return (
-

Web3Auth TON Telegram MiniApp

- {isLoggedIn ? ( - <> - {userInfoBox} - {tonAccountBox} - {signedMessageBox} - - ) : ( +
+
+ Web3Auth Logo + +
+
+

Web3Auth Telegram MiniApp

+
+
+

Seamless wallet access on any chain with Telegram. Just one click, and you're in!

+
+
+ + {isLoggingIn ? ( + ) : ( +
+ {isLoggedIn && ( + <> +
+ User avatar +
+
+

+ ID: {userData?.id} +

+ Telegram Logo +
+

+ Username: {userData?.username} +

+

+ Name: {userData?.firstName} {userData?.lastName || ""} +

+
+
+ +
copyToClipboard(tonAccountAddress || "", "account")} + > +
+

+ TON Account: + {tonAccountAddress} +

+ {copiedStates.account ? ( + + ) : ( + + )} +
+
+ +
copyToClipboard(signedMessage || "", "message")} + > +
+

+ Signed Message: + {signedMessage} +

+ {copiedStates.message ? ( + + ) : ( + + )} +
+
+ + )} +
)} + +
); ``` --- -### Step 8: Running and Testing the App +### Step 9: Running and Testing the App To run the app locally: @@ -455,7 +618,7 @@ For detailed steps on debugging your Telegram Mini App, refer to this --- -### Step 9: Deploy Your App +### Step 10: Deploy Your App Deploy this app to GitHub Pages, Vercel, or any other hosting service. For Vercel: @@ -475,7 +638,7 @@ server CORS configuration that we set up in **[Part 1](/guides/telegram-miniapp- --- -### Step 10: Setting Up a Telegram Bot +### Step 11: Setting Up a Telegram Bot To connect your Mini App to Telegram, you need to **create a bot** and set up a Mini App for it. @@ -508,6 +671,26 @@ Follow these steps: --- -This completes the client-side setup for the Telegram Mini App. By following these steps, you can -authenticate Telegram users, retrieve their TON blockchain account details, and allow them to -interact with decentralized applications via Web3Auth. +### Key Features of Web3Auth Web SDK Implementation + +The Web3Auth Web SDK provides several advantages for Telegram Mini App development: + +1. **Simplified Integration**: The Web SDK reduces boilerplate code and provides a streamlined + authentication flow. + +2. **Flexible Authentication**: The Web SDK supports multiple authentication methods, including + custom JWT authentication for seamless Telegram integration. + +3. **Automatic Chain Configuration**: The SDK automatically handles blockchain configurations, + making it easier to work with different networks like TON. + +4. **Enhanced Security**: The Web SDK includes additional security features and best practices out + of the box. + +5. **Better Error Handling**: Improved error handling and user feedback mechanisms. + +--- + +This completes the client-side setup for the Telegram Mini App using Web3Auth Web SDK. By following +these steps, you can authenticate Telegram users, retrieve their TON blockchain account details, and +provide a seamless user experience with modern UI components and automatic authentication flow. diff --git a/static/guides-banners/telegram-miniapp-client.png b/static/guides-banners/telegram-miniapp-client.png index a4575103e..a6d55ec9c 100644 Binary files a/static/guides-banners/telegram-miniapp-client.png and b/static/guides-banners/telegram-miniapp-client.png differ