---
title: Task 5.10 Telegram First-Class Authentication
tags: [audit, taskmaster, telegram, auth, testing]
---

# Task 5.10 Telegram First-Class Authentication

Date: 2026-05-24

## Scope

Task 5.10 implemented Telegram as a first-class Amanat auth provider.

- Backend now exposes `POST /api/auth/telegram`.
- The endpoint accepts Telegram Mini App `initData` or Telegram Login Widget payloads.
- Telegram signatures are verified server-side.
- Telegram-only users can be created without email/password.
- Standard Amanat JWT and refresh tokens are returned.
- Frontend Mini App sessions auto-authenticate from raw signed `initData`.
- The web login view includes a Telegram continuation button.

## Backend Implementation

Changed project: `backend`

- `src/models/User.ts`
  - `email` is now optional with a sparse unique index.
  - Added `authProvider: "email" | "google" | "telegram"`.
  - Added `telegramVerified`.
- `src/models/TelegramLink.ts`
  - Added `login_widget` as a supported source.
- `src/services/telegram/telegramService.ts`
  - Added Telegram Login Widget verification.
  - Added normalized Telegram auth identity helpers.
- `src/services/auth/authController.ts`
  - Added `telegramAuth`.
  - Auto-provisions Telegram users with nullable email.
  - Rejects replayed Mini App data, stale auth dates, invalid signatures, bot accounts, blocked links, and inactive users.
- `src/services/auth/authRoutes.ts`
  - Added public `POST /telegram`, mounted externally as `/api/auth/telegram`.

## Frontend Implementation

Changed project: `frontend`

- `src/lib/axios.ts`
  - Added `/auth/telegram` as a public endpoint.
  - Added `endpoints.auth.telegram`.
- `src/auth/context/jwt/action.ts`
  - Added `signInWithTelegram`.
  - Stores returned access/refresh tokens using the existing auth storage path.
- `src/sections/telegram/telegram-mini-app-shell.tsx`
  - Auto-authenticates Mini App sessions once from raw `initData`.
  - Shows an onboarding dialog for newly provisioned Telegram accounts.
  - Keeps standard sign-in/dashboard fallbacks.
- `src/auth/components/form-socials.tsx`
  - Added Telegram icon button.
- `src/auth/view/jwt/jwt-sign-in-view.tsx`
  - Added Telegram sign-in handler for both Mini App `initData` and browser Login Widget payloads.

## Security Notes

- Frontend never trusts `initDataUnsafe` for auth; it only sends raw signed `initData`.
- Backend validates Telegram HMAC signatures using the configured bot token.
- Mini App `auth_date` freshness and replay window are enforced before JWT issuance.
- Login Widget `auth_date` freshness is enforced.
- Telegram bot accounts are rejected.
- Blocked `TelegramLink` records are rejected with 403.
- Telegram phone numbers are neither requested nor persisted.
- High-risk escrow and wallet actions still use the existing protected API and step-up rules.

## Verification

Backend:

```bash
npm run typecheck
npx jest __tests__/telegram-auth.test.ts __tests__/telegram-service.test.ts --runInBand --forceExit
```

Result:

- Backend typecheck passed.
- `__tests__/telegram-auth.test.ts` passed.
- `__tests__/telegram-service.test.ts` passed.
- 14 targeted backend tests passed.

Frontend:

```bash
npm test -- __tests__/auth/telegram-auth-action.test.ts __tests__/sections/telegram/telegram-mini-app-shell.test.tsx --runInBand
npx tsc --noEmit -p tsconfig.json
```

Result:

- Targeted frontend Jest tests passed.
- 7 targeted frontend tests passed.
- Full frontend typecheck still reports unrelated pre-existing errors in payment UI code outside Task 5.10:
  - `src/components/payment/shkeeper-payment-widget.tsx`
  - `src/web3/components/provider-payment.tsx`

## Acceptance Coverage

| Requirement | Status |
| --- | --- |
| New Telegram user auto-provisions and receives JWT | Covered by backend test |
| Returning user authenticates via Mini App initData | Covered through same route and link lookup |
| Returning user authenticates via Login Widget | Covered by backend test |
| Replayed Mini App initData rejected | Covered by backend test |
| Stale `auth_date` rejected | Covered by backend test |
| Blocked Telegram account returns 403 | Covered by backend test |
| Existing email/password users unaffected | Covered by backend test |
| Email optional for Telegram users | Covered by backend test and sparse user model |
| `isNewUser` triggers onboarding overlay | Covered by frontend shell behavior |
| High-risk actions retain step-up requirements | No high-risk action code changed |

## Operational Follow-up

If a deployed MongoDB already has an old non-sparse unique `email` index, replace it with the sparse unique index before creating multiple Telegram-only users:

```js
db.users.dropIndex("email_1")
db.users.createIndex({ email: 1 }, { unique: true, sparse: true })
```

Run this only after confirming the existing index name in the target database.
