--- title: Authentication API tags: [api, auth, reference] --- # Authentication API All endpoints are mounted under `/api/auth/*` in `backend/src/app.ts`. The routes file is [`backend/src/services/auth/authRoutes.ts`](../../backend/src/services/auth/authRoutes.ts) and the WebAuthn sub-routes are in [`passkeyRoutes.ts`](../../backend/src/services/auth/passkeyRoutes.ts). Controller logic lives in [`authController.ts`](../../backend/src/services/auth/authController.ts) and [`authService.ts`](../../backend/src/services/auth/authService.ts). Two distinct identities are involved: a [[User]] (`models/User.ts`) and a [[TempVerification]] document that holds pending registration data until the email code is confirmed. Tokens are signed JWTs (access + refresh) created in `authService`. See [[Authentication Flow]] for the high-level lifecycle diagram. ## Registration ### POST /api/auth/register **Description:** Start a new registration. Creates a [[TempVerification]] document and emails an 8-digit verification code. The actual [[User]] is only created once the code is verified. **Auth required:** No **Request body:** ```ts { email: string; firstName?: string; // default "کاربر" lastName?: string; // default "جدید" role?: "buyer" | "seller"; // default "buyer" password?: string; // accepted now or at verify-email-code time referralCode?: string; // optional, links to referrer for [[Points API]] } ``` **Response 200:** ```json { "success": true, "message": "Verification code sent ...", "data": { "email": "x@y.z" } } ``` **Errors:** `400` validation, `409 USER_EXISTS` if email already registered. **Side effects:** - Upserts a `TempVerification` row. - Sends `emailService.sendVerificationCodeEmail`. - No socket emission yet (user does not exist). **Source:** `authController.register` ### POST /api/auth/verify-email-code **Description:** Confirms the registration code. Creates the [[User]], deletes the `TempVerification`, processes any referral, issues JWT tokens, and starts the session in Redis. **Auth required:** No **Request body:** ```ts { email: string; code: string; // 8 digits password?: string; // required if not provided at register } ``` **Response 200:** ```json { "success": true, "message": "Email verified", "data": { "user": { "_id": "...", "email": "...", "role": "buyer", ... }, "tokens": { "accessToken": "...", "refreshToken": "..." } } } ``` **Errors:** `400` invalid/expired code, `404` no pending verification, `409` email already taken. **Side effects:** - Creates [[User]], deletes `TempVerification`. - Calls [[Points API]] referral hook when `referralCode` was supplied (emits `referral-signup` to `user-`). - Stores refresh token in `user.refreshTokens`. - Welcome email via `emailService.sendWelcomeEmail`. ### GET /api/auth/verify-email/:token **Description:** Legacy URL-based verification (link in email). Marks `isEmailVerified=true`. **Auth required:** No **Response 200:** `{ "success": true, "message": "Email verified successfully" }` **Errors:** `400` invalid/expired token. ### POST /api/auth/resend-verification **Description:** Re-issues the 8-digit code for a pending or unverified user. **Auth required:** No **Request body:** `{ email: string }` **Response 200:** `{ "success": true, "message": "Verification code resent" }` **Errors:** `400` invalid email, `404` no user/temp record, `429` rate-limited (Redis). ### POST /api/auth/force-verify-user **Description:** Development-only helper to mark a user verified without going through email. **Auth required:** No (intended for dev only — gate with env in prod) ## Login & sessions ### POST /api/auth/login **Description:** Email/password login. Validates credentials with bcrypt, signs JWT pair, stores refresh token on user, returns sanitized user object. **Auth required:** No **Request body:** ```ts { email: string; password: string; } ``` **Response 200:** ```json { "success": true, "message": "Login successful", "data": { "user": { "_id": "...", "email": "...", "role": "buyer", "firstName": "..." }, "tokens": { "accessToken": "...", "refreshToken": "..." } } } ``` **Errors:** - `400` validation - `401` invalid credentials - `403` email not verified - `423` account locked (after repeated failures, tracked in Redis via `rateLimitService`) **Side effects:** - Updates `user.lastLoginAt`. - 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. **Auth required:** No (refresh token in body) **Request body:** `{ refreshToken: string }` **Response 200:** `{ "success": true, "data": { "tokens": { "accessToken": "...", "refreshToken": "..." } } }` **Errors:** `401` token expired / not present in user record, `403` user disabled. ### POST /api/auth/logout **Description:** Removes the current refresh token from the user record and clears the Redis session. **Auth required:** Bearer JWT **Response 200:** `{ "success": true, "message": "Logged out" }` **Side effects:** `redisService` session removed. ## Google OAuth ### POST /api/auth/google/signup **Description:** Verifies a Google ID token, creates a new [[User]] (no password), optionally links a referral, returns JWT tokens. **Auth required:** No **Request body:** ```ts { googleToken: string; role?: "buyer" | "seller"; referralCode?: string; } ``` **Response 200:** Same shape as `verify-email-code` response. **Errors:** `400` invalid Google token, `409` email already registered (suggest sign-in instead). ### POST /api/auth/google/signin **Description:** Verifies a Google ID token and signs in an existing user. Will not create a new account. **Auth required:** No **Request body:** `{ googleToken: string }` **Response 200:** `{ success, data: { user, tokens } }` **Errors:** `400` invalid token, `404` no user with that Google email. ## Passkey / WebAuthn Routes are nested under `/api/auth/` via `passkeyRoutes`. Service: `passkeyService.ts`. ### POST /api/auth/passkey/authenticate/challenge **Description:** Generates a sign-in challenge that the browser/authenticator will sign. No `userId` required — the assertion will identify the user. **Auth required:** No **Response 200:** `{ "success": true, "challenge": { /* PublicKeyCredentialRequestOptions */ } }` ### POST /api/auth/passkey/authenticate **Description:** Verifies the WebAuthn assertion and, on success, returns a JWT pair. **Auth required:** No **Request body:** `{ challenge, assertion }` (assertion is the browser's `navigator.credentials.get()` output). **Response 200:** `{ "success": true, "userId": "...", "user": { ... }, "tokens": { ... } }` **Errors:** `400` missing fields, `404` `Passkey not found`, `500` verification error. ### POST /api/auth/passkey/register/challenge **Description:** Generates a registration challenge for the authenticated user. **Auth required:** Bearer JWT **Response 200:** `{ "success": true, "challenge": { /* PublicKeyCredentialCreationOptions */ } }` ### POST /api/auth/passkey/register **Description:** Verifies a new passkey registration and stores the credential on the user. **Auth required:** Bearer JWT **Request body:** `{ challenge, credential }` **Response 200:** `{ "success": true, "message": "Passkey registered successfully" }` ### GET /api/auth/passkey/list **Description:** Returns the calling user's registered passkeys (id, label, created date). **Auth required:** Bearer JWT **Response 200:** `{ "success": true, "passkeys": [...] }` ### DELETE /api/auth/passkey/:passkeyId **Description:** Removes a passkey by id. **Auth required:** Bearer JWT **Response 200:** `{ "success": true, "message": "Passkey removed successfully" }` ## Password management ### POST /api/auth/request-password-reset **Description:** Generates a reset token, stores it on the user, and emails a reset link plus a numeric code. **Auth required:** No **Request body:** `{ email: string }` **Response 200:** `{ "success": true, "message": "Password reset email sent" }` (always returns success to avoid email enumeration). **Side effects:** `emailService.sendPasswordResetEmail`; rate-limited per IP via Redis. ### POST /api/auth/reset-password **Description:** Sets a new password using a token from the reset email. Wipes refresh tokens. **Auth required:** No **Request body:** ```ts { token: string; password: string; // 6+ chars, mixed case + digit } ``` **Response 200:** `{ "success": true, "message": "Password updated" }` **Errors:** `400` invalid/expired token or weak password. ### POST /api/auth/reset-password-with-code **Description:** Alternative reset flow using a numeric code instead of a tokenised URL. **Auth required:** No **Request body:** `{ email, code, password }` **Response 200:** `{ "success": true }` ### POST /api/auth/change-password **Description:** Authenticated password change. **Auth required:** Bearer JWT **Request body:** ```ts { currentPassword: string; newPassword: string; // 6+ chars, mixed case + digit } ``` **Response 200:** `{ "success": true, "message": "Password updated" }` **Errors:** `400` validation, `401` wrong current password. **Side effects:** Clears `user.refreshTokens` (forces re-login on other devices). ## Current user / profile ### GET /api/auth/profile **Description:** Returns the full sanitized [[User]] document for the caller. **Auth required:** Bearer JWT **Response 200:** `{ "success": true, "data": { /* User */ } }` ### PUT /api/auth/profile (and POST /api/auth/update-profile) **Description:** Updates the caller's profile (first/last name, phone, bio, website, language/currency preferences). **Auth required:** Bearer JWT **Request body:** Partial profile, see `updateProfileValidation`: ```ts { firstName?: string; // 2-50 lastName?: string; // 2-50 profile?: { phone?: string; // E.164-ish bio?: string; // <=500 website?: string; // URL }; preferences?: { language?: "en" | "fa" | "ar"; currency?: "USD" | "EUR" | "IRR" | "AED"; }; } ``` **Response 200:** Updated user. **Errors:** `400` validation. ## Account deletion ### DELETE /api/auth/account **Description:** Permanently deletes the caller's account after re-authenticating with password. **Auth required:** Bearer JWT **Request body:** `{ password: string }` **Response 200:** `{ "success": true, "message": "Account deleted" }` **Errors:** `401` bad password. **Side effects:** Removes [[User]] document, clears Redis session, cascades configured by `dataCleanupService`. ## Error codes summary | HTTP | App code | Meaning | | --- | --- | --- | | 400 | `Validation Error` | `express-validator` rejected the body | | 401 | — | Bad credentials / missing token / invalid Telegram signature | | 403 | — | Email not verified, insufficient role, or blocked Telegram account | | 409 | `USER_EXISTS` | Email already in use | | 409 | `TELEGRAM_REPLAY` | Reused Telegram Mini App `initData` (replay protection) | | 423 | — | Account temporarily locked after failed logins | | 429 | — | Rate-limited (auth tier: 10 req / 15 min / IP) | See [[Error Codes]] for the global error shape.