بنناجح
المرحلة 2: الـ Tokens والـ JWT والـ OAuth · الدرس 3 من 4 · 35 دقيقة

الـ Logout والـ Refresh والتخزين

الـ JWT ميزته إن السيرفر مش فاكر عنه حاجة، وده بالظبط اللي بيخلي الـ logout صعب. الدرس ده بيحل المشكلة بالـ Access والـ Refresh tokens، وبيجاوب على سؤال بيتسأل في كل إنترفيو: تخزن الـ token فين؟ وفي الآخر المقارنة الكاملة: Session ولا JWT.

في الدرس ده هتتعلم
  • تشرح ليه الـ JWT صعب يتلغي، وتعرف 4 حلول وتمن كل واحد
  • تفهم Access و Refresh tokens، و Rotation، و Reuse Detection
  • تقارن localStorage و Memory و HttpOnly Cookie قدام XSS و CSRF
  • تختار بين Session و Opaque Token و JWT وإنت فاهم التمن

1. مشكلة الـ Logout (Token Revocation)

المستخدم دوس “تسجيل خروج”. مع الـ Session، بتمسح الصف وخلاص. لكن مع الـ JWT، الـ token لسه سليم وتوقيعه صح وصالح لحد الـ exp. لو حد كان سرقه، هيفضل يستخدمه.

نفس المشكلة لما تعمل ban لمستخدم، أو تشيل صلاحية الأدمن من حد، أو المستخدم يغيّر الباسورد عشان شاك إن حسابه اتسرق.

افتكر المحاكي اللي في درس الـ Tokens: الـ Opaque وقع فوراً، والـ JWT فضل شغال لحد الـ exp. الحلول:

الحل الفكرة التمن
عمر قصير الـ access token يعيش 5 لـ 15 دقيقة بس محتاج refresh token (تحت)
Denylist تخزّن الـ jti بتاع الـ tokens الملغية في Redis لحد ما الـ exp بتاعها يعدّي بقيت بتسأل store في كل request، يعني رجعت stateful
Token Version عمود token_version في users، وبيتحط في الـ token. لما تزوّده، كل الـ tokens القديمة تبطل lookup للمستخدم في كل request
تاريخ آخر logout ترفض أي token الـ iat بتاعه أقدم من آخر “خروج من كل الأجهزة” نفس التمن

الـ JWT ميزته إنه stateless، وعشان تلغيه لازم ترجّع حتة state. وعشان كده العمر القصير هو خط الدفاع الأول.

2. Access Token و Refresh Token

فكّر في تذكرة دخول يومية في معرض، واشتراك سنوي متشال في درج. كل يوم بتطلّع تذكرة جديدة بالاشتراك، والتذكرة هي اللي بتوريها لكل بوابة. لو التذكرة اتسرقت، هتبوظ آخر اليوم. والاشتراك نفسه مش بيخرج من الدرج غير عند شباك واحد.

الـ Access بيخلص والـ Refresh بيجددهمحاكاة
0

دوس ▶ شغّل، أو امشي خطوة خطوة بالأسهم.

التطبيقClientAuth serverrefresh storeAPIResourcelogin1access (15m) + refresh R1 (30d)2request + A132004request + A1 (expired)5401 token expired6POST /token/refresh + R17R1 valid → mark used8A2 + R29retry + A21020011loginA1 + R1A1200A1401R1A2 + R2A2200

Refresh Token Rotation و Reuse Detection

كل مرة تستخدم refresh token، بتاخد واحد جديد والقديم بيبطل. طب ليه؟

  1. هاكر سرق R1. المستخدم الحقيقي استخدم R1 الأول وخد R2.
  2. الهاكر يحاول يستخدم R1. السيرفر يلاحظ إن R1 اتستخدم قبل كده.
  3. ده معناه إن فيه نسختين من نفس الـ token في الدنيا، يعني فيه سرقة. فالسيرفر يلغي العيلة كلها (R1 و R2 وأي حاجة اتولدت منهم)، والمستخدم يعمل login تاني.

جرّب السيناريوهين: اسرق refresh وسيب الوقت يعدّي وبعدين خلي الهاكر يستخدمه. وبعدين اعمل reset، واسرق، وخلي الهاكر يستخدمه على طول قبل المستخدم.

Refresh Token Rotationالوقت بيعدّي
Access Token A1
15 دقيقة
جيب الهاكرفاضي
عيلة الـ Refresh Tokens (على السيرفر)
    شغّل الوقت، واتفرج على الـ access بيخلص ويتجدد لوحده. وبعدين اسرق refresh.

    كده حتى لو الـ refresh token اتسرق، السرقة بتتكشف أول مرة الاتنين يستخدموه.

    Access Token Refresh Token
    العمر دقايق أيام أو أسابيع
    بيتبعت لمين كل API Auth server بس
    النوع غالباً JWT Opaque متخزن في الداتابيز
    تقدر تلغيه بتستنى يخلص فوراً

    الـ Access Token قصير عشان لو اتسرق يبوظ بسرعة، والـ Refresh Token بيتغيّر مع كل استخدام عشان لو اتسرق السرقة تنكشف.

    3. تخزن الـ Token فين في المتصفح؟

    اختار موقف، وشوف الـ token في كل مكان هيحصله إيه:

    تخزن الـ token فين؟سؤال في كل إنترفيو
    حصل إيه؟
    localStoragelocalStorage.setItem("token", …)
    🔑 token

    —

    Memorylet token = … (متغيّر في JS)
    🔑 token

    —

    HttpOnly CookieSet-Cookie: token=…; HttpOnly
    🔑 token

    —

    اختار موقف، وشوف الـ token في كل مكان هيحصله إيه.
    المكان الميزة العيب
    localStorage سهل، وبيفضل موجود بعد ما تقفل المتصفح أي JavaScript في الصفحة يقراه، فأي ثغرة XSS تسرقه
    Memory (متغيّر في JS) XSS أصعب شوية يوصله بيضيع مع أول refresh للصفحة
    HttpOnly Cookie الـ JavaScript ميقدرش يقراه خالص المتصفح بيبعته لوحده، فالـ CSRF رجع، ومحتاج SameSite و CSRF token

    لاحظ إننا رجعنا لنفس المكان. أأمن طريقة لتخزين token في المتصفح هي cookie فيها HttpOnly. يعني عملياً بقت session تاني.

    التوصيات العملية

    • SPA بتاعتك وعلى نفس الـ domain (زي shop.com و api.shop.com): استخدم session cookies عادي. ده بالظبط “SPA mode” في Sanctum.
    • SPA بتكلم APIs كتير من برا: نمط اسمه BFF (Backend For Frontend). سيرفر صغير بتاعك شايل الـ tokens، والمتصفح بيكلمه بـ session cookie.
    • تطبيق موبايل: الـ token في التخزين الآمن بتاع النظام، يعني Keychain في iOS و Keystore في Android.

    الـ JWT في localStorage مش “أحدث” من الـ session. هو بس شال حماية HttpOnly. فلو الـ client متصفح وعلى نفس الـ domain، الـ session cookie لسه أحسن اختيار.

    4. Session ولا JWT؟

    Session JWT
    الداتا متخزنة فين على السيرفر جوه الـ token مع المستخدم
    كل request lookup في الـ store تشيك توقيع بس
    الـ Logout فوري صعب
    تغيير الصلاحيات بيبان فوراً بيستنى الـ token يخلص
    Services كتير محتاجة store مشترك كل service تتأكد لوحدها
    تطبيقات الموبايل تنفع بس مش طبيعية طبيعية
    CSRF محتاج حماية مش مشكلة لو في header
    XSS HttpOnly بتحميه في localStorage بيتسرق
    الحجم رقم صغير ممكن يبقى كبير، وبيتبعت مع كل request

    إمتى تختار إيه

    • Session: موقع Blade زي shop-lab، أو SPA بتاعتك على نفس الـ domain.
    • Opaque Token زي Sanctum: تطبيق موبايل، أو API لعملاء، ومحتاج تلغي tokens بسهولة.
    • JWT: services كتير بتتأكد من غير ما تكلم بعض، أو token جاي من Identity Provider زي Google في OpenID Connect.

    مفيش حل أحسن من التاني بشكل مطلق. الـ Session بتديك تحكم، والـ JWT بيديك توزيع، واختار على حسب اللي إنت محتاجه فعلاً.

    أسئلة الإنترفيو

    فكّر في إجابتك الأول، وبعدين افتح السؤال.

    01إزاي تعمل logout لـ JWT؟

    مفيش طريقة stateless بالكامل. الأساس عمر قصير للـ access token مع refresh token تقدر تلغيه. ولو محتاج إلغاء فوري: denylist بالـ jti في Redis لحد الـ exp، أو token version على المستخدم. وكل حل من دول بيرجّع شوية state.

    02ليه فيه Access Token و Refresh Token؟

    الـ access token بيتبعت مع كل request فاحتمال سرقته أكبر، فبنخليه قصير. الـ refresh token بيتبعت لمكان واحد بس ونادراً، وبيتخزن على السيرفر فنقدر نلغيه، وبيجدد الـ access token من غير ما المستخدم يعمل login.

    03يعني إيه Refresh Token Rotation؟

    كل استخدام للـ refresh token بيدي واحد جديد ويبطّل القديم. ولو القديم اتستخدم تاني، يبقى فيه نسختين يعني سرقة، فالسيرفر يلغي العيلة كلها ويجبر المستخدم يعمل login.

    04تخزن الـ token فين في الـ SPA؟

    localStorage مكشوف لأي XSS. HttpOnly cookie أأمن من XSS بس بترجّع CSRF فمحتاج SameSite و CSRF token. لو الـ SPA بتاعتي وعلى نفس الـ domain أستخدم session cookies (زي Sanctum SPA). ولو APIs برا أستخدم BFF.

    05Session ولا JWT؟

    JWT مش session أحسن. بينقل الـ state من السيرفر للـ client، فبيكسب تأكيد من غير داتابيز وبيخسر سهولة الإلغاء. بختار Session لموقع أو SPA على نفس الـ domain، و Opaque token للموبايل والـ APIs اللي محتاجة إلغاء سهل، و JWT لما services كتير محتاجة تتأكد من غير ما تكلم بعض.

    علّم عليه لما تقدر تجاوب أسئلة الإنترفيو من غير ما تبص.