Skip to content

Thirdweb's in-app wallets in Telegram using custom authentication.

Notifications You must be signed in to change notification settings

IntoTheVerse/telegram-mini-app

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 

Repository files navigation

Group 2 (1)

thirdweb Telegram Mini App Example

thirdweb SDK Discord

Authenticate your users and generate a smart wallet without ever leaving Telegram. This example app showcases thirdweb's custom authentication and smart accounts from within a Telegram mini app.

Getting Started

This project assumes some basic knowledge of TypeScript, Next.js App Router, and Connect SDK.

Environment Variables

  1. Create your .env by running cp .env.example .env in both the /next-app and /telegram-bot directories.

  2. Create a client ID from the thirdweb dashboard and add it to your .env as NEXT_PUBLIC_THIRDWEB_CLIENT_ID. Follow the instructions in each .env file to set up your environment variables.

Set the authentication endpoint

This project uses a powerful thirdweb feature called Authentication Endpoints. It uses your own API endpoint to generate a wallet for users on successful authentication. All the code for this is written for you in this project, you'll just need to set the endpoint in your thirdweb dashboard.

To use Custom Authentication Endpoints, you'll need to be on the Growth Plan. If you have questions about the plan options or want to try it out, reach out to our team.

Navigate to the In-App Wallets page on the dashboard and select your project from the dropdown. This should be the same project your clientId is from. Then click the "Configuration" tab and scroll down to "Custom Authentication Endpoint" and enable the toggle. You'll then see a field to enter your endpoint.

Screenshot 2024-08-02 at 2 24 00 AM

While testing the project locally, you'll need a publicly exposed endpoint to authenticate through. We recommend using a tool like ngrok to create a public endpoint that forwards traffic to your local server. Forward your traffic to http://localhost:3000 (where your app will run locally).

Once you have your ngrok or similar endpoint, add it to the Authentication Endpoint field as [YOUR FORWARDING ENDPOINT]/api/auth/telegram, the route this app uses to perform authentication.

You're now ready to run the project!

When you deploy to production (or any live URL), you'll modify this authentication endpoint to be your actual live URL. You could also create a separate thirdweb project for local development and production.

Run the project

You're now ready to test the project! First, you'll need to install the dependencies. Run the following command in both the /next-app and /telegram-bot directories:

pnpm install

Now, run pnpm dev in both the /next-app and /telegram-bot directories. This will start the Next.js app and the Telegram bot.

You should see the app at http://localhost:3000. Try messaging the /start command to the bot you configured with the Bot Father in Telegram.

When you press "Launch App", your mini app should open and a wallet should be generated for you.

Going to production

Once you've implemented this flow into your own app, there are a few changes you'll need to make to go to production.

Remember to go to your project in the In-App Wallets configuration tab and update the auth endpoint to be [YOUR PRODUCTION URL]/api/auth/telegram. In this case, do include https:// in the URL.

Now, you're ready to deploy your app and Telegram bot to production!

How it works

All the logic for this example can be found in telegram-bot/src/bot/start.ts, /next-app/src/app/api/auth/telegram/route.ts, and /next-app/src/app/login/telegran/page.tsx.

When a user requests a new link to the app, we generate a unique signature for them based on their username and the current time. This signature can then be verified in your Next.js app's backend. This is how the user will authenticate their telegram profile, no password or extra login steps required!

const adminAccount = privateKeyToAccount({
  privateKey: process.env.ADMIN_SECRET_KEY as string,
  client: createThirdwebClient({ clientId: process.env.THIRDWEB_CLIENT_ID as string }),
});

// ...

const username = ctx.from?.username;
const expiration = Date.now() + 600_000; // valid for 10 minutes
const message = JSON.stringify({
    username,
    expiration
});
const authCode = await adminAccount.signMessage({
    message
});

When the user clicks their unique login link, they're first sent to /login/telegram to be authenticated. When the user lands on this page, the search parameters are immediately send to your custom authentication endpoint for verification (we'll look at how that works next). If the user is successfully authenticated, the wallet will connect. Otherwise, the connection will fail. Because of the seamless login experience with Telegram, normal users will never face a failed login. Everything happens seamlessly behind the scenes without passwords or one-time codes.

const { connect } = useConnect();

await connect(async () => {
    
    await wallet.connect({
        client,
        strategy: "auth_endpoint",
        payload: JSON.stringify({
            signature: searchParams.signature,
            message: searchParams.message,
        }),
        encryptionKey: process.env.NEXT_PUBLIC_AUTH_PHRASE as string,
    });
    return wallet;
});

The backend authentication sends a POST request with the signature and message to the /api/auth/telegram endpoint. There, we use the same admin account to verify the original signature and expiration time (to prevent replay attacks). If the signature is valid, we can trust that we verified this user form within our Telegram bot. We return a unique userId to generate their wallet, which in this case is their Telegram username.

export async function verifyTelegram(signature: string, message: string) {
    const metadata = JSON.parse(message);
    
    if (!metadata.expiration || metadata.expiration < Date.now()) {
        return false;
    }

    if (!metadata.username) {
        return false;
    }

    const isValid = await verifySignature({
        client,
        address: adminAccount.address,
        message: message,
        signature,
    });

    if (!isValid) {
        return false;
    }

    return metadata.username;
}

Now that the user is connected, they'll be redirected to the homepage where they can use their wallet in your app.

Documentation

Support

For help or feedback, please visit our support site

About

Thirdweb's in-app wallets in Telegram using custom authentication.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • TypeScript 96.9%
  • CSS 1.6%
  • JavaScript 1.5%