ابحث عن أمر لتشغيله...

منطقة الأدمن في مدونتي محمية مرتين. الواجهة بتسجّل دخولي بـ session. الـ API بيتحقق من token. ولا نظام فيهم يعرف حاجة عن التاني، وفي route صغير للتبديل واقف بينهم. المقال ده هو الـ setup الحقيقي — النظامين، والرحلتين، والمقايضات اللي قبلتها.
أنا مكنتش ناوي أبني نظامين auth. الواجهة Next.js، وكانت محتاجة session: أدمن مسجّل دخول بيتنقل بين الصفحات، وdialog للدخول، وزرار للخروج. الـ API معمول بـ ASP.NET Core، وكان محتاج tokens ملهاش حالة: كل request يثبت نفسه بنفسه، من غير session على السيرفر ندوّر عليها. إعادة كتابة أي طرف عشان يطابق التاني كانت هتكلف أكتر من بناء جسر بينهم. فبنيت الجسر.
الواجهة بتستخدم better-auth. ليها جداولها الخاصة — user وsession وaccount وverification — في نفس قاعدة بيانات PostgreSQL بتاعة محتوى المدونة. الـ session بتعيش سبعة أيام وبتتجدد لما يعدي عليها يوم. الدخول بيحصل من dialog الواجهة نفسها، مع GitHub كاختيار اجتماعي. بعد الدخول، المتصفح بيمسك cookie الـ session، والتطبيق بيبقى عارف أنا مين في كل صفحة.
الـ session كويسة للواجهة. بتعيش مع الـ refresh، وبتشتغل عبر الصفحات، وإلغاؤها صف واحد في جدول. لكنها وحشة للـ API: الـ API هيضطر يفهم مخزن session الواجهة، وكل request هيجرّ مشاكل الواجهة للـ backend.
الـ API بيستخدم JWT Bearer authentication. كل request محمي لازم يشيل token في الـ Authorization header، والـ API بيتحقق من أربع حاجات قبل ما يثق فيه: التوقيع، والـ issuer، والـ audience، وتاريخ الانتهاء. لو أي واحدة فيهم فشلت، الـ request بيقف هنا. وendpoints الأدمن بتضيف بوابة زيادة: سياسة AdminOnly اللي بتطلب role الأدمن.
الـ token كويس للـ API. مكتفي بذاته: الـ API بيتحقق منه من التوقيع بس، من غير lookup ومن غير مخزن session مشترك. لكنه وحش للواجهة: بينتهي بسرعة، ومش ممكن إلغاؤه بمسح صف، وتخزينه في المتصفح قرار لازم تاخده وانت واعي.
دي اللي بيحصل لما أسجّل دخول. بدخل من dialog الواجهة. better-auth بتعمل session والمتصفح بيمسك الـ cookie. مع تحميل التطبيق، الـ session provider بيقرا الـ session دي — وعلى طول بينادي route صغير في Next.js اسمه exchange-token.
الـ route ده بيشتغل على السيرفر، مش في المتصفح. بيقرا الـ session من جهة السيرفر، وبعدين يصدر JWT للـ .NET API: الـ id والإيميل والاسم بتوعي، موقّعين بسرّ مشترك بين الطرفين، وصلاحيته خمستاشر دقيقة. المتصفح بيخزّن الـ token ده وبيستخدمه في مكالمات الـ API. وسرّ التوقيع عمره ما بيوصل للمتصفح.
الخمستاشر دقيقة مقصودة. الـ session بتعيش أيام؛ وtoken الـ API بيعيش دقايق. لو token اتسرب، شباكه صغير. ولما ينتهي، الواجهة بتبدّل الـ session بواحد جديد — الـ session هي الإثبات طويل العمر، والـ token هو التصريح قصير العمر.
كل مكالمة API من المتصفح بتعدي على helper واحد. بيقرا الـ token من التخزين ويلزقه كـ Bearer header. وبعدين الـ request بيمشي في pipeline الـ API بالترتيب: authentication الأول، وبعدين authorization. الـ authentication بتجاوب «الـ token ده حقيقي؟» والـ authorization بتجاوب «الهوية دي مسموح لها هنا؟»
token ناقص أو بايظ معناه 401: أثبت انت مين تاني. token سليم من غير الـ role المطلوبة معناه 403: أنا عارف انت مين، والإجابة لسه لأ. الفصل بين الاتنين مهم — واحدة مشكلة دخول، والتانية مشكلة صلاحيات، والتعامل معاهم كأنهم حاجة واحدة بيضيّع ساعات في الـ debugging.
نظام واحد كان هيبقى أسهل في الشرح. نظامان بيخلّوا كل طرف يحتفظ بالـ auth المناسب ليه: sessions للصفحات، وtokens للـ APIs. والجسر route واحد، ولا طرف اضطر يغيّر طريقة شغله.
والتكاليف حقيقية. بقى فيه session-ين نفكر فيهم مش واحد. الأعمار مش متفقة — سبعة أيام قصاد خمستاشر دقيقة — فأخطاء الانتهاء بتظهر في مكانين. والـ token قاعد في تخزين المتصفح، يعني أي script شغال على الصفحة ممكن يقراه. وأي مطور جديد على الكود لازم يتعلم الجسر قبل ما قصة الـ auth تبقى مفهومة. قبلت التكاليف دي لأن البديل كان إعادة كتابة auth شغال في طرف من الطرفين.
التوقيع، بالسرّ المشترك — مفيش توقيع، مفيش ثقة.
الـ issuer والـ audience — الـ token لازم يكون بتاعي، ومقصود للـ API بتاعتي.
الانتهاء — إجباري مش اختياري، وقصير.
السرّ على السيرفر بس — المتصفح عمره ما بيشوفه.
endpoints الأدمن بتطلب الـ role زيادة — الـ authentication مش authorization.
ولا حاجة من دي غريبة. دي قائمة التحقق الافتراضية، مطبقة من غير اختصارات. والقرار الوحيد اللي مش افتراضي هو التقسيم نفسه — والتقسيم هو اللي بيخلي الباقي سهل التفكير فيه.
بابان وجسر واحد. الواجهة بتحرس الصفحات بـ session. والـ API بيحرس البيانات بـ token. وroute التبديل بيترجم بينهم، والسرّ المشترك هو الحاجة الوحيدة المشتركة بينهم. لو انت مشغّل واجهة وbackend منفصلين، غالبًا مش محتاج نظام auth واحد. انت محتاج نظامين متفقين على حاجة واحدة بالظبط.
منطقة الأدمن في مدونتي محمية مرتين: sessions من better-auth في المتصفح، وJWT Bearer على الـ API، وroute صغير للتبديل بينهم. ده الـ setup الحقيقي، بالرحلات والمقايضات.
فكرت إيه اللي بيحصل لما تكتب عنوان موقع في المتصفح؟ تعالى نتبع الطلب من جهازك لحد ما يوصل للسيرفر، ونستكشف البنية التحتية اللي بتشغّل المنصة بتاعتي الجديدة.
شغّلت CQRS مع MediatR في نظامين حقيقيين — وسيبته برّه التالت عن قصد. المهارة مش إنك تعرف الباترن، المهارة إنك تعرف حدوده فين.