diff --git a/.taskmaster/docs/prd-telegram-phone-auth.md b/.taskmaster/docs/prd-telegram-phone-auth.md new file mode 100644 index 0000000..f9ef150 --- /dev/null +++ b/.taskmaster/docs/prd-telegram-phone-auth.md @@ -0,0 +1,146 @@ +# PRD: Telegram Phone-Number Authentication + +## Problem + +The current Telegram integration treats Telegram as a *secondary identity layer*: a user must already hold an Amanat email-password (or Google OAuth) account before they can link their Telegram identity. This creates unnecessary friction for users who arrive from Telegram, have never heard of Amanat, and reasonably expect the Mini App to just work — as every other well-built Telegram Mini App does. + +Telegram accounts are phone-number-verified by Telegram itself. When the backend successfully verifies Mini App `initData`, it has already established that the requester holds a specific Telegram account tied to a phone number. That is sufficient identity to create and authenticate an Amanat account without asking for an email or password. + +## Goal + +Allow users to sign in to Amanat using their Telegram identity as the primary credential — with zero separate signup step. This applies to: + +1. **Telegram Mini App context** — `initData` is auto-available and already cryptographically verified. +2. **Telegram Login Widget** — the standard web widget that lets users authenticate via Telegram on any browser page; returns a signed payload verifiable against the bot token. + +In both cases the user's phone-verification is owned by Telegram; Amanat trusts the signed assertion and does not re-verify the phone number itself. + +## Platform assumptions + +- Telegram Mini App `initData` is signed with HMAC-SHA-256 keyed on `HMAC-SHA-256("WebAppData", BOT_TOKEN)`. Server-side verification is already implemented in `telegramService.ts`. +- Telegram Login Widget returns `{id, first_name, last_name, username, photo_url, auth_date, hash}`. Hash is `HMAC-SHA-256(data_check_string, SHA256(BOT_TOKEN))`. The same bot token covers both flows. +- Telegram user IDs are stable, globally unique integers that do not change even if the user changes username or phone number. +- Telegram does not expose the raw phone number to third-party apps — the ID is the stable identity anchor. + +Reference docs: +- Telegram Login Widget: https://core.telegram.org/widgets/login +- Mini Apps initData: https://core.telegram.org/bots/webapps#validating-data-received-via-the-mini-app + +## What changes + +### Backend + +**New endpoint: `POST /auth/telegram`** + +Accepts one of: +- `{ initData: string }` — from Mini App context +- `{ id, first_name, last_name, username, photo_url, auth_date, hash }` — from Login Widget + +Steps: +1. Verify signature (reuse `verifyMiniAppInitData` for initData path; add `verifyTelegramLoginWidget` for widget path). +2. Extract `telegramUserId` (stable integer). +3. Look up `TelegramLink` by `telegramUserId`. +4. **If link found and active** → load the linked Amanat user → issue JWT + refresh token (same format as `POST /auth/login`). +5. **If no link found** → auto-provision a new Amanat user: + - `email`: `null` (nullable; add index exclusion for null values) + - `firstName` / `lastName`: from Telegram profile + - `username`: `tg_` as stable internal handle + - `role`: `buyer` (default; user can change) + - `isEmailVerified`: `false` — set a flag `telegramVerified: true` instead + - `status`: `active` + - `authProvider`: `telegram` + - Create `TelegramLink` record in the same transaction. + - Issue JWT + refresh token. +6. On success, always upsert `TelegramLink.lastSeenAt` and update name/username fields from latest Telegram profile. +7. Return: `{ token, refreshToken, user, isNewUser: boolean }` — `isNewUser: true` signals the frontend to show an onboarding nudge (optional email capture, preferred language, currency). + +**User model changes:** + +- `email`: make nullable (`type: String, sparse: true` — allows multiple null values in a unique sparse index) +- Add `telegramVerified: Boolean` (default `false`) +- Add `authProvider: 'email' | 'google' | 'telegram'` field +- Existing email-based users are unaffected; their `authProvider` defaults to `'email'` + +**Rate limiting and security:** + +- Apply the same replay protection already in `telegramService.ts` to this endpoint. +- Rate limit: 10 requests per IP per minute, 5 per Telegram user ID per minute. +- Log all auto-provisioning events as audit records. +- Reject `auth_date` older than `TELEGRAM_MINIAPP_MAX_AGE_MS` (already configurable). + +**Blocked account handling:** + +- If `TelegramLink.status === 'blocked'` → return 403 with `ACCOUNT_BLOCKED` code. +- If the linked Amanat user is suspended/deleted → return 403 with `ACCOUNT_SUSPENDED`. + +### Frontend + +**Mini App auto-login (inside Telegram):** + +When `window.Telegram?.WebApp?.initData` is non-empty: +1. Skip the login page entirely. +2. POST `initData` to `/auth/telegram`. +3. Store the returned JWT in the existing auth context. +4. If `isNewUser === true`, show a lightweight onboarding overlay inside the Mini App to capture optional email and preferred settings before routing to the main app. + +**Web login page — "Continue with Telegram" button:** + +- Add a "Continue with Telegram" button alongside the existing Google button. +- Clicking it opens the Telegram Login Widget in a popup (`window.open` or inline script tag method). +- On callback, POST the widget payload to `/auth/telegram`. +- This works on any browser, not only inside Telegram. + +**Auth types update:** + +```typescript +// auth/types.ts additions +export interface User { + // ... existing fields ... + telegramVerified: boolean; + authProvider: 'email' | 'google' | 'telegram'; + telegramUsername?: string; +} +``` + +**Onboarding nudge (post-Telegram-auth):** + +New users created via Telegram auth should be shown a non-blocking screen: +- Optional: "Add an email for account recovery" (not required) +- Optional: preferred language and currency +- Skippable — routing to the main app without completing it is fine + +## Non-goals + +- Do not expose the user's raw phone number. +- Do not require email for Telegram-authenticated users. +- Do not use Telegram auth as a bypass for high-risk actions (release, payout address change, dispute resolution still require step-up confirmation as per task 5.6/5.8 policy). +- Do not auto-merge a Telegram-provisioned account with an existing email account unless the user explicitly initiates account linking from settings. + +## Account merge and collision handling + +| Scenario | Behavior | +|---|---| +| Telegram user arrives, no existing account | Auto-provision, create TelegramLink, return `isNewUser: true` | +| Telegram user arrives, TelegramLink already exists | Auth as linked user, update last-seen | +| Email user opens Mini App, not yet linked | Show "Link your Telegram" prompt (existing task 5.2 flow) — do NOT auto-merge | +| Two Telegram accounts try to link to same email user | Reject second; return 409 DUPLICATE_TELEGRAM_LINK | +| Same Telegram user tries to auth with two different app accounts | Impossible by design — TelegramLink.telegramUserId is unique | + +## Acceptance criteria + +1. A new Telegram user can complete authentication inside the Mini App without entering an email or password. +2. A returning Telegram user gets the same JWT session whether they authenticate via Mini App `initData` or the web Login Widget. +3. `POST /auth/telegram` rejects replayed `initData` within the existing replay window. +4. `POST /auth/telegram` rejects `auth_date` older than the configured max-age. +5. Blocked Telegram accounts receive a 403 response; they cannot circumvent it by unlinking and re-linking. +6. Auto-provisioned users have `authProvider: 'telegram'` and no email; existing email users are unaffected. +7. Admin UI (task 5.7) can distinguish `authProvider: telegram` users and shows `telegramVerified` status. +8. A Telegram-authed user who later adds an email can then also log in via email — both paths converge to the same user record. +9. High-risk actions still require the step-up policy regardless of auth provider. +10. The "Continue with Telegram" button is visible on the web login page in non-Mini-App contexts. + +## Dependencies + +- Task 5.2 (identity linking model) — TelegramLink model and verifyMiniAppInitData are already done; this task extends the auth path, not the linking model. +- Task 5.8 (security controls) — replay protection, rate limits, and audit logging from that task apply here too. +- Task 5.6 (high-risk action policy) — must not be weakened. diff --git a/.taskmaster/tasks/task-5.md b/.taskmaster/tasks/task-5.md index 00bf045..d678671 100644 --- a/.taskmaster/tasks/task-5.md +++ b/.taskmaster/tasks/task-5.md @@ -19,3 +19,4 @@ Subtasks: 7. Add admin and support surface for Telegram-originated cases. 8. Add security, compliance, and abuse controls for Telegram. 9. Prepare QA, rollout, analytics, and launch operations. +10. Implement Telegram as first-class authentication provider. ✅ Done 2026-05-24. diff --git a/.taskmaster/tasks/tasks.json b/.taskmaster/tasks/tasks.json index 19e4620..35a7656 100644 --- a/.taskmaster/tasks/tasks.json +++ b/.taskmaster/tasks/tasks.json @@ -617,14 +617,29 @@ "testStrategy": "See Telegram-native PRD acceptance criteria.", "parentId": "undefined", "updatedAt": "2026-05-24T09:18:26.638Z" + }, + { + "id": 10, + "title": "Implement Telegram as first-class authentication provider", + "description": "Add a POST /auth/telegram endpoint and frontend login flow so users can authenticate with Amanat using only their Telegram identity — no email or password required.", + "details": "Source PRD: .taskmaster/docs/prd-telegram-phone-auth.md. Backend: create POST /auth/telegram that accepts Mini App initData or Telegram Login Widget payload, verifies the signature (reuse verifyMiniAppInitData; add verifyTelegramLoginWidget for the widget path), looks up TelegramLink by telegramUserId, and either authenticates the linked user or auto-provisions a new Amanat account (authProvider: telegram, telegramVerified: true, nullable email via sparse unique index). Returns JWT + refreshToken + isNewUser flag. Apply existing replay protection and rate limits. User model: make email nullable (sparse index), add authProvider and telegramVerified fields. Frontend: auto-detect Telegram Mini App context and skip login page; POST initData to /auth/telegram; show lightweight onboarding overlay for new users (optional email, language, currency). Add 'Continue with Telegram' button on web login page alongside Google OAuth. Security: blocked Telegram accounts return 403 regardless of re-linking attempts; high-risk action step-up policy is unchanged; never expose raw phone number.", + "status": "done", + "dependencies": [ + 2, + 8 + ], + "priority": "high", + "testStrategy": "Verify: new Telegram user auto-provisions and receives JWT; returning user authenticates via both initData and Login Widget; replayed initData is rejected; stale auth_date is rejected; blocked account returns 403; existing email-password users are unaffected; email remains optional (not required) for Telegram-authed users; isNewUser flag triggers onboarding overlay; high-risk actions still require step-up confirmation.\n\nImplemented verification: backend typecheck; backend targeted Jest __tests__/telegram-auth.test.ts and __tests__/telegram-service.test.ts; frontend targeted Jest __tests__/auth/telegram-auth-action.test.ts and __tests__/sections/telegram/telegram-mini-app-shell.test.tsx. Full frontend typecheck still has unrelated pre-existing payment icon/payload errors outside Task 5.10.", + "parentId": "5", + "updatedAt": "2026-05-24T11:59:32.372Z" } ], - "updatedAt": "2026-05-24T09:18:26.638Z" + "updatedAt": "2026-05-24T11:59:32.372Z" } ], "metadata": { "version": "1.0.0", - "lastModified": "2026-05-24T09:18:26.638Z", + "lastModified": "2026-05-24T11:59:32.372Z", "taskCount": 5, "completedCount": 4, "tags": [ @@ -632,4 +647,4 @@ ] } } -} \ No newline at end of file +} diff --git a/02 - Data Models/User.md b/02 - Data Models/User.md index e786052..660b0e5 100644 --- a/02 - Data Models/User.md +++ b/02 - Data Models/User.md @@ -16,12 +16,14 @@ The core identity document for every actor in the marketplace: buyers, sellers, | Field | Type | Required | Default | Validation | Index | Description | | --- | --- | --- | --- | --- | --- | --- | -| `email` | String | yes | — | lowercase, trim | unique | Primary login identifier. | -| `password` | String | no | — | minlength 6 | — | Hashed password. Optional to support passkey-only accounts. | +| `email` | String | no | — | lowercase, trim | unique, sparse | Primary email login identifier. Nullable for Telegram-only accounts. | +| `password` | String | no | — | minlength 6 | — | Hashed password. Optional to support passkey-only, Google, and Telegram accounts. | | `firstName` | String | no | `"کاربر"` | trim | — | Persian default ("user"). | | `lastName` | String | no | `"جدید"` | trim | — | Persian default ("new"). | | `role` | String | yes | `"buyer"` | enum: `admin` / `buyer` / `seller` | yes | Authorisation tier. | | `isEmailVerified` | Boolean | no | `false` | — | — | Set to true after [[TempVerification]] is consumed. | +| `authProvider` | String | yes | `"email"` | enum: `email` / `google` / `telegram` | yes | Provider used to create the account. Existing email/password accounts remain `email`; Telegram-only users are `telegram`. | +| `telegramVerified` | Boolean | no | `false` | — | — | Set when Telegram identity has been signature-verified and linked through `TelegramLink`. | | `emailVerificationToken` | String | no | — | — | — | Legacy token-based email verification. | | `emailVerificationCode` | String | no | — | — | — | OTP code for email verification. | | `emailVerificationCodeExpires` | Date | no | — | — | — | Expiry for `emailVerificationCode`. | @@ -76,10 +78,12 @@ The core identity document for every actor in the marketplace: buyers, sellers, ## Indexes -Defined explicitly (in addition to the implicit `email` unique index): +Defined explicitly: +- `{ email: 1 }` unique sparse — allows multiple Telegram-only users without email while preserving uniqueness for email-bearing users. - `{ role: 1 }` — `backend/src/models/User.ts:178` - `{ status: 1 }` — `backend/src/models/User.ts:179` +- `{ authProvider: 1 }` — supports provider-level account reporting and cleanup. > [!warning] Missing indexes > The schema currently defines only `role` and `status` indexes. The `referralCode`, `referredBy`, and `points.level` indexes documented below are **not yet present** in `User.ts`: diff --git a/03 - API Reference/Authentication API.md b/03 - API Reference/Authentication API.md index a4d1629..8d12cf6 100644 --- a/03 - API Reference/Authentication API.md +++ b/03 - API Reference/Authentication API.md @@ -121,6 +121,37 @@ Two distinct identities are involved: a [[User]] (`models/User.ts`) and a [[Temp - Pushes refresh token onto `user.refreshTokens`. - Redis session start via `sessionService`. +### POST /api/auth/telegram + +**Description:** First-class Telegram authentication. Accepts Telegram Mini App `initData` or a Telegram Login Widget payload, verifies the Telegram signature server-side, and signs the user into Amanat without requiring email or password. +**Auth required:** No +**Request body:** +```ts +// Mini App +{ initData: string; role?: "buyer" | "seller" } + +// Login Widget +{ loginWidget: { id: string; first_name?: string; username?: string; auth_date: string; hash: string }; role?: "buyer" | "seller" } +``` +**Response 200/201:** +```json +{ + "success": true, + "data": { + "user": { "_id": "...", "authProvider": "telegram", "telegramVerified": true }, + "tokens": { "accessToken": "...", "refreshToken": "..." }, + "isNewUser": true, + "telegram": { "userId": "10001", "username": "alice", "source": "miniapp" } + } +} +``` +**Errors:** `400` missing payload, `401` invalid/stale signature, `403` blocked Telegram account or inactive Amanat account, `409 TELEGRAM_REPLAY` reused Mini App `initData`, `429` rate-limited. +**Side effects:** +- Creates a Telegram-only [[User]] when no active `TelegramLink` exists. The user has no email, `authProvider: "telegram"`, and `telegramVerified: true`. +- Upserts `TelegramLink` for the Telegram ID and updates last-seen metadata. +- Stores the refresh token on the user document. +- Does not expose phone numbers; Telegram phone data is not requested or persisted. + ### POST /api/auth/refresh-token **Description:** Exchanges a refresh token for a new access token. Rotates the refresh token. diff --git a/04 - Flows/Authentication Flow.md b/04 - Flows/Authentication Flow.md index b4e1304..4489734 100644 --- a/04 - Flows/Authentication Flow.md +++ b/04 - Flows/Authentication Flow.md @@ -95,10 +95,27 @@ sequenceDiagram | Method | Endpoint | Source | |---|---|---| | `POST` | `/api/auth/login` | `backend/src/services/auth/authRoutes.ts:22` → `authController.login` | +| `POST` | `/api/auth/telegram` | `authRoutes.ts` → `authController.telegramAuth` | | `POST` | `/api/auth/refresh-token` | `authRoutes.ts:24-27` → `authController.refreshToken` | | `POST` | `/api/auth/logout` | `authRoutes.ts:68` → `authController.logout` (protected) | | `GET` | `/api/auth/profile` | `authRoutes.ts:69` → `authController.getProfile` | +## Telegram first-class auth flow + +Telegram is now a peer auth provider alongside email/password, Google, and passkeys. + +1. The Telegram Mini App shell reads raw signed launch data from `window.Telegram.WebApp.initData`; browser login can submit a Telegram Login Widget payload. +2. The frontend posts the raw signed payload to `POST /api/auth/telegram`; it never trusts `initDataUnsafe` for authentication. +3. Backend verifies the Telegram signature: + - Mini App uses `verifyMiniAppInitData()` with the Telegram WebAppData HMAC algorithm. + - Login Widget uses `verifyTelegramLoginWidget()` with the Telegram Login Widget HMAC algorithm. +4. Backend rejects stale `auth_date`, bot accounts, replayed Mini App `initData`, and blocked `TelegramLink` records. +5. If an active `TelegramLink` exists, backend signs in that Amanat user. If no link exists, backend creates a Telegram-only user with nullable email, `authProvider: "telegram"`, `telegramVerified: true`, then creates the link. +6. Backend issues the standard access token and refresh token pair. The frontend stores them in `localStorage` under `accessToken` and `refreshToken`, then hydrates the current session. +7. If `isNewUser=true`, the Mini App opens a lightweight onboarding overlay and points the user to account settings for optional email, language, currency, and wallet details. + +High-risk actions are unchanged: escrow release, refund, dispute-sensitive, and wallet-sensitive operations still use the existing protected backend authorization and step-up gates. Telegram auth only establishes the user session. + ## Database writes - **`users` collection**: `lastLoginAt` updated; `refreshTokens` array gains one entry per successful login or refresh. diff --git a/09 - Audits/Task 5.10 Telegram First-Class Authentication.md b/09 - Audits/Task 5.10 Telegram First-Class Authentication.md new file mode 100644 index 0000000..fad9a5b --- /dev/null +++ b/09 - Audits/Task 5.10 Telegram First-Class Authentication.md @@ -0,0 +1,127 @@ +--- +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. + +## 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. +- 6 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. diff --git a/PRD - Telegram Phone Number Authentication.md b/PRD - Telegram Phone Number Authentication.md new file mode 100644 index 0000000..64e9e8c --- /dev/null +++ b/PRD - Telegram Phone Number Authentication.md @@ -0,0 +1,67 @@ +# PRD: Telegram Phone Number Authentication + +> Source spec: `.taskmaster/docs/prd-telegram-phone-auth.md` +> Related task: **Task 5.10** — Implement Telegram as first-class authentication provider + +--- + +## Problem + +The current Telegram integration is a *secondary linking layer*: users must already have an Amanat email/password or Google account before they can connect Telegram. This breaks the natural Telegram Mini App user journey — someone who opens the Mini App from Telegram has already proven phone ownership to Telegram and reasonably expects to be authenticated with zero extra signup friction. + +## Core idea + +Telegram accounts are phone-number-verified. When the backend verifies `initData` from the Mini App (already implemented), it has cryptographic proof that the requester controls a specific Telegram identity. That proof is sufficient to create and sign in to an Amanat account — no email, no password required. + +The same principle applies to the **Telegram Login Widget**, the standard web-based flow that lets users authenticate on any browser page by confirming from their Telegram app. + +## Two auth paths covered + +| Context | Mechanism | Already have? | +|---|---|---| +| Inside Telegram Mini App | `initData` HMAC-SHA-256 (already verified server-side) | Partial — used for linking only | +| Any browser (web login page) | Telegram Login Widget → signed callback | Missing | + +Both paths converge at a new `POST /auth/telegram` endpoint that: verifies the signature → looks up or creates the Amanat user → issues a JWT session. + +## New user provisioning + +When a Telegram user arrives with no existing account: + +- Account is auto-created (`authProvider: telegram`, `telegramVerified: true`) +- No email required — email column becomes nullable (`sparse` unique index) +- Name pre-filled from Telegram profile +- Role defaults to `buyer`; user can change +- A non-blocking onboarding screen offers (but does not require) email capture and preference setup + +## What does NOT change + +- Existing email/password and Google OAuth users are unaffected +- High-risk actions (release, refund, dispute resolution) still require step-up confirmation regardless of auth provider +- Telegram is not made the *only* auth method — it becomes an equal alternative +- Raw phone number is never exposed to Amanat; Telegram user ID is the stable identity anchor + +## Key acceptance criteria + +1. New Telegram user completes auth inside Mini App without entering email or password. +2. Returning Telegram user gets the same session whether using Mini App or web Login Widget. +3. Replay protection and max-age validation apply to this endpoint. +4. Blocked Telegram accounts receive 403 and cannot circumvent by re-linking. +5. Auto-provisioned users have `authProvider: telegram`; existing users are unaffected. +6. "Continue with Telegram" button visible on the web login page. +7. High-risk action step-up policy is unchanged. + +## Collision and merge rules + +| Scenario | Behavior | +|---|---| +| New Telegram user | Auto-provision + TelegramLink | +| Returning Telegram user | Auth as linked user | +| Email user opens Mini App (not yet linked) | Prompt to link (existing task 5.2 flow) | +| Same Telegram account on two app users | Rejected — TelegramLink.telegramUserId is unique | + +## See also + +- `.taskmaster/docs/prd-telegram-phone-auth.md` — full specification with endpoint contract, model changes, and frontend integration details +- `PRD - Platform Audit Remediation Plan (2026-05-24).md` — security baseline this feature must not weaken +- Task 5.2 (Identity linking), Task 5.8 (Security controls) diff --git a/Taskmaster/Tasks/task-5-10.md b/Taskmaster/Tasks/task-5-10.md new file mode 100644 index 0000000..3773159 --- /dev/null +++ b/Taskmaster/Tasks/task-5-10.md @@ -0,0 +1,43 @@ +--- +taskmaster_id: "5.10" +status: "done" +priority: "high" +depends_on: ["5.2", "5.8"] +parent_id: "5" +source: "taskmaster" +generated_at: "2026-05-24T09:18:26.638Z" +completed_at: "2026-05-24" +--- + +# 5.10 - Implement Telegram as first-class authentication provider + +- [x] 5.10 - Implement Telegram as first-class authentication provider #taskmaster #priority/high #status/done ⏫ 🆔 tm-5.10 + +## Metadata + +| Field | Value | +| --- | --- | +| Taskmaster ID | 5.10 | +| Status | done | +| Priority | high | +| Dependencies | 5.2, 5.8 | +| Parent | 5 | + +## Description + +Add `POST /api/auth/telegram` and frontend login flow so users can authenticate with Amanat using only Telegram identity, without email or password. + +## Details + +Backend verifies Telegram Mini App `initData` and Telegram Login Widget payloads, checks/reuses `TelegramLink`, auto-provisions Telegram-only users with nullable email, `authProvider: "telegram"`, and `telegramVerified: true`, and returns the normal JWT/refresh-token pair plus `isNewUser`. + +Frontend auto-authenticates Telegram Mini App launches from raw signed `initData`, adds a Telegram login action, and shows a lightweight onboarding dialog for new Telegram users. + +## Verification + +- Backend typecheck passed. +- Backend targeted Jest passed: `__tests__/telegram-auth.test.ts`, `__tests__/telegram-service.test.ts`. +- Frontend targeted Jest passed: `__tests__/auth/telegram-auth-action.test.ts`, `__tests__/sections/telegram/telegram-mini-app-shell.test.tsx`. +- Full frontend typecheck still has unrelated pre-existing payment UI errors outside this task. + +See [[Task 5.10 Telegram First-Class Authentication]] for the audit report.