DEV Community

Serhii
Serhii

Posted on Originally published at botservice.biz

Auth Your React Mini App with Telegram: InitData + JWT Validation

Introduction

Integrating a Telegram Mini App into a modern web application requires more than just embedding the app in a web page. For secure applications, you must verify that the request genuinely originates from the official mini app and that the user identity is authenticated. This guide walks through building an authentication flow where a React front-end reads the initData sent by Telegram, validates its integrity and origin, extracts a JWT, and confirms the caller's identity before granting any protected actions.

The core challenge lies in bridging two different stacks: a React front-end running in the browser and a PHP backend handling the actual authorization logic. The bridge is the initData parameter that Telegram passes when a user opens the mini app. It contains a cryptographic signature over the data and can also carry a JWT for additional claims. By verifying both the signature and the JWT on the server, you create a defense-in-depth mechanism that prevents impersonation attacks and ensures that only legitimate users can trigger protected operations.

This tutorial assumes familiarity with React development and basic PHP web frameworks (Laravel, Symfony, or plain PHP with a web server). The backend examples use PHP's native extensions but follow patterns compatible with most frameworks.

Understanding Telegram Mini App InitData

When a user launches a Telegram Mini App, Telegram sends them a deep-link containing the initData query parameter. This parameter is a base64-encoded string that includes:

  • User identifier (id) – the unique numeric ID assigned to the user within the mini app ecosystem.
  • Init data – arbitrary key-value pairs that can hold session tokens, JWTs, or other metadata.
  • Signature – an HMAC-SHA256 digest computed over the non-signature portion of initData, signed with the app's secret key. This proves the data hasn't been tampered with and comes from the official client.
initData = base64encode("       ,  " + user_id + " : " + jwt + " ,  " . sign(user_secret, initData_without_signature))
Enter fullscreen mode Exit fullscreen mode

The signature allows the backend to independently verify that the initData truly came from the registered Telegram Mini App. If the signature doesn't match, the request should be rejected immediately.

Beyond signature verification, many implementations embed a JWT inside initData. A well-structured JWT typically contains claims such as sub (the user ID), exp (expiration), and optionally role or permissions. By decoding and validating this JWT on the backend, you add another layer of security: even if an attacker manages to forge the signature (which they cannot without the secret), they still won't have access to privileged operations because their JWT lacks the required permissions.

Backend: Validating InitData and JWT

Step 1: Receive and Decode initData

The first thing your PHP endpoint does is read the incoming request parameters. For a POST to /api/miniapp/auth, you expect something like:


json
{
  "initData": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIy",
  "secret": "your_app_secret_key\

---

Need a production-ready Telegram bot or Mini App? [BotCreator](https://botservice.biz) can help.
Enter fullscreen mode Exit fullscreen mode

Top comments (0)