رفتن به محتوای اصلی

احراز هویت

ورود اصلی این سرویس با شمارهٔ موبایل است:

  1. POST /api/auth/send-otp با شمارهٔ کاربر فراخوانی می‌شود. این مرحله فقط شماره را ثبت می‌کند و اگر کاربر تازه باشد، ردیف کاربر را می‌سازد؛ هیچ متادیتای حسابی (نام، ایمیل، دستگاه و…) در این مرحله ذخیره نمی‌شود.
  2. POST /api/auth/verify-otp با شماره و کد ۶ رقمی فراخوانی می‌شود. اولین تأییدِ موفق، تقویم اصلی حساب را می‌سازد. متادیتای حساب هم از همین‌جا، بعد از اثبات مالکیت شماره، قابل اعمال است.

مسیر POST /api/auth/login با email/password هم وجود دارد؛ فیلدهایش را در مرجع API ببینید.

دو نکتهٔ مرزی:

  • deviceId نامعتبر، پیش از هر تغییری در پروفایل، FCM یا وضعیت تأیید، درخواست را ناموفق می‌کند.
  • کد توسعه (OTP آزمایشی): کد فقط وقتی APP_ENV دقیقاً development یا test باشد در پاسخ برمی‌گردد؛ اگر APP_ENV تنظیم نشده یا هر مقدار دیگری باشد، پنهان می‌ماند. کد در console لاگ نمی‌شود و با RNG رمزنگاری‌شده ساخته می‌شود. در محیط واقعی debug را فعال نکنید و NODE_ENV را جایگزال APP_ENV نگیرید.

نشست دستگاه​

سرور دو حالت نشست دارد و رفتارشان فرق می‌کند؛ این دو را با هم اشتباه نگیرید.

حالت ۱ — نشست دستگاه‌محور (مسیر فعلی و توصیه‌شده): در verify-otp یا login یک شیء device بفرستید که uid (هویت پایدارِ آن نصب، نه شناسهٔ کاربر یا سخت‌افزار) و platform (ANDROID/WEB/IOS) دارد؛ نام دستگاه اختیاری است. با این کار refresh token به آن دستگاه وصل می‌شود و از فهرست دستگاه‌ها قابل ابطال است.

حالت ۲ — نشست قدیمی روی User: اگر device نفرستید، refresh token روی خود ردیف کاربر ذخیره می‌شود و هر ورود قدیمیِ دیگری می‌تواند آن را جایگزین کند.

در POST /api/auth/refresh:

  • refreshToken همیشه لازم است.
  • deviceUid اختیاری است؛ اگر نفرستید، از خود توکنِ امضاشده و تأییدشده استخراج می‌شود.
  • مقدار ارسالی deviceUid باید با اتصال واقعی توکن یکی باشد؛گرنه چرخش ناموفق است.
مسیررفتار
POST /api/auth/refreshچرخش جفت توکن؛ هر دو مقدار تازه را ذخیره کنید
POST /api/auth/logoutابطال refresh دستگاهِ مشخص (یا در نبود آن، refresh قدیمی حساب)
GET /api/auth/meاطلاعات حساب با access token معتبر

مشخصات توکن‌ها:

  • access token در سرصفحهٔ Authorization: Bearer ارسال می‌شود؛ عمر پیش‌فرض ۱۵ دقیقه است.
  • refresh token عمر پیش‌فرض ۹۰ روز دارد.
  • هر دو عمر با JWT_ACCESS_EXPIRES_IN و JWT_REFRESH_EXPIRES_IN قابل تنظیم‌اند.
  • چرخش‌های refresh هم‌زمان را در کلاینت یکی کنید (یک پرواز در آن واحد): استفادهٔ دوباره از refresh توکنی که همین خانواده قبلاً چرخانده‌اند، به‌عنوان reuse تشخیص داده می‌شود و کل نشست دستگاه باطل می‌شود. ابطال دستگاه مرجع کامل است.

بازیابی بدون حذف داده​

قاعدهٔ کلی: شکست احراز هویت یا شبکه، مجوز پاک‌کردن دادهٔ محلی کاربر نیست.

  • 401 روی درخواست عادی: یک refresh مشترک بزنید (تا دو درخواست هم‌زمان نسازید) و همان درخواست را تکرار کنید.
  • 401/403 روی خود refresh: نشست از بین رفته؛ کاربر باید دوباره وارد شود — بدون پاک‌کردن خودکار دادهٔ محلی و outbox.
  • شبکه، timeout، 429، 5xx یا پاسخ نامعتبر (خوانده‌نشدنی/ناقص): همه شکست گذرایند؛ توکن و outbox را نگه دارید و بعداً تلاش کنید.
  • خروج وقتی تغییر ارسال‌نشده هست: تصمیم باید صریح باشد — ارسال کامل، خروجی گرفتن، یا دورریز با تأیید کاربر. پاسخ دیررسِ حساب قبلی نباید وارد حساب بعدی شود.

نکتهٔ امنیتی وب: توکن‌ها در localStorage نگه داشته می‌شوند، نه storage رمزنگاری‌شده. جزئیات پیاده‌سازی: وب و اندروید.

مرجع سرور: apps/api/src/routes/auth.ts و apps/api/src/services/deviceService.ts؛ کلاینت وب: apps/calendar-web/src/lib/apiClient.ts.