Skip to Content

المصادقة

يستخدم أمل مصادقة Bearer JWT بلا ملفات تعريف ارتباط للجلسات. يُقرَن رمز وصول قصير العمر برمز تجديد طويل العمر ومتدوّر.

الرمزالعمريُخزَّن أينيتدوّر؟
رمز الوصول15 دقيقة (expiresIn: 900)لدى العميل فقط؛ بلا حالةلا
رمز التجديد7 أيامعلى الخادمنعم، عند كل استخدام

التسجيل

POST /api/auth/register للتمهيد فقط. يُنشئ الاستدعاء الأول مسؤولًا بنطاق SUPER ويعيد زوج رموز. بعد ذلك يُغلَق التسجيل: أي استدعاء لاحق يعيد 403 مع code: "PERMISSION_DENIED".

organizationId مطلوب لكل دور عدا المسؤول الأول بنطاق SUPER الذي يحذفه. ويُنشأ كل المستخدمين اللاحقين عبر إنشاء المستخدمين، لا عبر التسجيل.

تسجيل الدخول

POST /api/auth/login بجسم { email, password } ← 200 AuthTokensResponse ({ accessToken, refreshToken, expiresIn, tokenType }). تعيد بيانات الاعتماد الخاطئة 401.

حماية القوة الغاشمة تعيد 401 + Retry-After، لا 429. بعد 5 محاولات فاشلة لكل بريد خلال 15 دقيقة تُقفَل نقطة النهاية وتستجيب بـ 401 وترويسة Retry-After (عدد ثواني الانتظار). تظهر ترويسات X-RateLimit-* بعد أول محاولة فاشلة. لا تتوقّع 429 صريحًا من هذه الواجهة.

يوجد طلب دخول كامل مع استجابته (curl و TypeScript) في البدء السريع ← الخطوة 2.

استخدام رمز الوصول

أرسل رمز الوصول مع كل طلب محمي:

curl https://localhost:3000/api/auth/me \ -H "Authorization: Bearer <accessToken>"

يعيد GET /api/auth/me هويتك إضافةً إلى مصفوفة permissions[] التي تحكم كل نقطة نهاية (MeResponse).

التجديد والتدوير

POST /api/auth/refresh بجسم { refreshToken } ← AuthTokensResponse جديد. رموز التجديد تتدوّر: يُلغى الرمز القديم عند الاستخدام. إعادة استخدام رمز تجديد مُدوَّر تعيد 401 وتُلغي الجلسة (كشف سرقة). خزّن دائمًا أحدث رمز تجديد من آخر استجابة.

تسجيل الخروج

POST /api/auth/logout (يتطلّب رمز وصول صالحًا) يُلغي الجلسة على الخادم. رموز الوصول غير قابلة للإلغاء الفردي؛ فهي قصيرة العمر بحسب التصميم، لذا تنتهي ببساطة.

إعادة تعيين كلمة المرور

تدفّق من خطوتين، آمن ضد التعداد:

  1. POST /api/auth/password-reset بجسم { email } ← دائمًا 200 (لا يكشف أبدًا إن كان البريد موجودًا) ← يُرسَل رابط سحري (صلاحية ساعة واحدة).
  2. POST /api/auth/password-reset/confirm بجسم { token, newPassword } ← يعيد تعيين كلمة المرور ويُلغي كل الجلسات القائمة.

دخول الطالب بالرمز السريع

لسهولة الاستخدام في الصف الأول، يسجّل الطلاب الدخول بلا بريد أو كلمة مرور:

curl -X POST https://localhost:3000/api/auth/student/quickcode \ -H "Content-Type: application/json" \ -d '{ "quickCode": "472", "classId": "clx4z2k0u0000xyz1234abcde" }'

POST /api/auth/student/quickcode برمز سريع من رقمين (01–99) + classCode رمز الصف من 6 أرقام يعيد زوج رموز بنطاق الطالب (QuickCodeLoginResponse مع tokens وstudentId وclassId). الرمزان زوج اعتماد واحد: رمز الصف يصل داخل الرابط الذي يدفعه المعلّم (/student-login?class=<classCode>)، ويكتب الطالب رمزه الخاص فقط.

  • رمز الطالب لكل صف (فريد بين طلاب الصف الفعّالين، فيتّسع الصف لـ 99 طالبًا كحدّ أقصى) ولا ينتهي أبدًا؛ وهو أيضًا كلمة مرور الطالب في الدخول المنزلي.
  • رمز الصف صالح سنة كاملة (365 يومًا) من إصداره. ويمكن تجديده يدويًا من لوحة رابط الصف إذا وصل الرابط إلى غير المعنيّين (أو POST /api/classes/{classId}/login-code/rotate)، ونسخ رابط منتهٍ يجدّده تلقائيًا. يتوقف الرابط القديم فورًا، ولا تتغيّر رموز الطلاب عند تجديد رمز الصف.
  • رمز غير صالح أو منتهٍ (للطالب أو للصف) يعيد 401 مع code: "QUICKCODE_INVALID_OR_EXPIRED"؛ وكثرة المحاولات تعيد 401 مع code: "QUICKCODE_RATE_LIMIT".
  • GET /api/auth/student/class-preview?classCode= (عام ومحدود المعدّل) يعيد اسمَي الصف والمدرسة لصفحة الدخول؛ ورمز صف منتهٍ يعيد 410 مع code: "CLASS_CODE_EXPIRED".
  • صيغة الطلب المباشرة بـ classId مرفوضة في الإنتاج.

تسجيل الدخول عبر Google

يستطيع المستخدمون المستوردون من نظام إدارة التعلم تسجيل الدخول بحساباتهم على Google. يستخدم التدفق PKCE ورمز تسليم قصير العمر:

  1. البدء: GET /api/auth/google/start?loginHint=<email> يعيد { redirectUrl }. وجِّه متصفّح المستخدم إلى redirectUrl.
  2. إعادة التوجيه: يعيد Google التوجيه إلى GET /api/auth/google/callback. يُصدر الخادم معاملَ ?code= لمرة واحدة لمدة 60 ثانية ويعيد توجيه المتصفح إلى التطبيق.
  3. التبادل: يُرسل التطبيق فورًا POST بـ { code } إلى POST /api/auth/google/exchange ويستقبل AuthTokensResponse معياريًا.

GET /api/auth/google/start يعيد 503 عندما لا يكون GOOGLE_CLIENT_ID مُضبَّطًا في البيئة. تتحكّم قائمة النطاقات المسموح بها (allowedGoogleDomains على سجل المؤسسة) في حسابات Google المقبولة.

ما الموجود (وغير الموجود) في الرمز

يحمل الـ JWT الـ userId (sub) والـ organizationId (orgId) ورمز الدور (role) ومعرّف الجلسة (sid)، إضافةً إلى مطالبتَي iat/exp المعيارية. لا يُدرَج اسم أو بريد أو صف. اقرأ هذه من GET /api/auth/me. لا يوجد تدوير لسرّ الرمز / مطالبة sv في الموجة الأولى (مؤجَّل لموجة لاحقة)، لا تبنِ على وجوده.