إنتقل إلى المحتوى الرئيسي

تفاصيل المستخدم

الخلفية​

GET /api/v1/users هو route خدمة المصادقة العام لسؤال «لمن هذا الـ token؟». كُتب قبل الترحيل، ولا توجد واجهة من Shukah تقابله. ومع x-auth-from: SHUKAH يفحص token ويُرجع الملف الشخصي للعميل.

وهو مهم للترحيل لأن خدمات backend أخرى تستخدمه. فـ order-v2 وخدمة النقاط تستدعيانه لتحويل الـ token الذي استلمتاه إلى عميل. وقد يكون ذلك الـ token من Shukah أو JWT من Locate، لذا يقرّر هذا الـ route أي tokens تقبلها routes النقاط في order-v2.

الميزة​

أرسل الـ token في Authorization وحدّد أي backend يتحقق منه في x-auth-from. المستدعون يرسلون SHUKAH.

  • order-v2: حارس الملف الشخصي (profile guard) لديه، الذي يحمي كثيرًا من routes العميل مثل الطلبات وبطاقات الهدايا، يستدعي هذا الـ route مع x-auth-from: SHUKAH.
  • خدمة النقاط: يستدعي الـ client middleware فيها هذا الـ route لمعرفة هوية المستدعي. وهو يرسل x-auth-from من إعداده الخاص AUTH_VERIFY_APPLICATION (SHUKAH افتراضيًا)، ويقرأ معرّف العميل من الإجابة، ويعطي مستدعيَه 401 عندما لا يجيب هذا الـ route بـ 2xx.
  • مستدعون آخرون: غير موثّق بعد.

التطبيق نفسه لا يستدعي هذا الـ route: فنسخة التطبيق اللحظية بتاريخ 2026-02-26 لا تحتوي أي استدعاء له. ولا يحتاج التطبيق إلى إرسال x-auth-from إلى routes النقاط في order-v2، لأن order-v2 وخدمة النقاط تضبطانه بنفسيهما عندما تستدعيان هذا الـ route.

وأي tokens تعمل يعتمد على إعداد العميل auth_source (shukah أو locate)، الذي يملكه locate-go. وإذا تعذّر على الخدمة قراءة الإعداد، تستخدم locate.

الـ Tokenauth_source ليس locateauth_source هو locate
token من Shukahيعمل. تطلب الخدمة من Shukah فحصه (GET /maeda/api/verify-token) وتُرجع إجابة Shukah دون تغيير.يعمل عندما يكون الـ token أحد tokens الخدمة النشطة المخزَّنة. لم يُلتقط.
JWT من Locateيعمل فقط إذا كانت Shukah تعرف الـ JWT، لأن الخدمة ما زالت تسأل Shukah.لا يعمل أبدًا في الشيفرة المثبَّتة (pinned): فهو يحصل دائمًا على 401. وهذا عيب (defect).

على dev، في 2026-10-01، حصل token من Shukah وJWT من Locate كلاهما على 200 بالـ body نفسه. وفي 2026-10-02 تغيّر ذلك. فقد كان auth_source على dev هو shukah (مقروءًا من إعدادات العميل العامة)، لذا يمرّر هذا الـ route الـ token إلى Shukah على dev. أما routes النقاط في order-v2، التي تستدعي هذا الـ route، فأعطت JWT من Locate 401 وtoken من Shukah 200: فلم تعد Shukah على dev تقبل الـ JWT (استنتاج؛ لم يُستدعَ هذا الـ route نفسه مع x-auth-from في ذلك اليوم). ومع ضبط auth_source على locate سيفشل الـ JWT أيضًا، بسبب العيب المذكور في الجدول. فعلى dev اليوم لا يعمل هنا إلا token من Shukah، ولا يجعل أي إعداد وحده JWT من Locate يعمل.

GET /api/v1/users​

endpoint جديد — لا يوجد ما يقابله في Shukah.

الطلب (Request)​

الحقلالموضعالنوعمطلوبالقيودالوصف
Authorizationheaderstringنعم، إلا في MERCHANTBearer <token>. والجزء الثاني بعد المسافة هو الـ token. والمفقود يعطي 401.الـ token المراد فحصه. وعلى dev اليوم لا يمر إلا token من Shukah (2026-10-02).
x-auth-fromheaderstringنعمواحدة من SHUKAH أو LOCATE_V2 أو ADMIN_SHUKAH أو ADMIN_LOCATE أو MERCHANT. وهي حساسة لحالة الأحرف: فمع وجود Authorization، تعطي shukah الخطأ 422. يستخدم المستدعون SHUKAH، وبقية هذه الصفحة عنها.أي backend يتحقق من الـ token.
access-token وclient وuidheaderstringMERCHANT فقطالثلاثة كلها مطلوبة لـ MERCHANT.جلسة تاجر (merchant).

الاستجابة (Response)​

مع x-auth-from: SHUKAH، 200 مع الملف الشخصي للعميل ككائن مجرد. ويعتمد الـ body على كيفية فحص الخدمة للـ token:

كيف فُحص الـ tokenBody
تمرير (Relay): auth_source ليس locate.body الخاص بـ verify-token من Shukah نفسه، دون تغيير. وعلى dev كانت له الحقول الـ 13 نفسها في التحقق من الـ token: status هو active وsex هو 0 أو 1 أو 2، والأعلام 0 أو 1.
محليًا، token من Shukah: auth_source هو locate.شكل مختلف: status هو ACTIVE الخام، وsex هو MALE أو FEMALE أو UNKNOWN، والأعلام الأربعة قيم منطقية (boolean)، ويُحذف odoo_id عندما لا يكون للعميل واحد. لم يُلتقط.
محليًا، JWT من Locate: auth_source هو locate.لا نجاح: 401 في كل مرة في الشيفرة المثبَّتة.
{
"client_id": 356259,
"odoo_id": "1342170",
"contact_phone": "+966500000000",
"status": "active",
"email_address": "user@example.com",
"first_name": "Test",
"last_name": "User",
"sex": 1,
"birth_date": "1990-01-01",
"receive_offers": 0,
"push_enabled": 0,
"is_food_truck_user": 1,
"is_cod_disabled": 0
}

التُقط على dev، 2026-10-01 (العميل 356259)، مرة مع token من Shukah ومرة مع JWT من Locate: وأعاد الاستدعاءان هذا الـ body. واستُبدلت الحقول الشخصية. وفي 2026-10-02 حصل JWT من Locate على 401 من routes النقاط التي تستدعي هذا الـ route، فهذا الـ body هو ما يحصل عليه token من Shukah اليوم.

الأخطاء​

HTTPBodyمتى
401{"status":401,"message":"Unauthorization"}لا يوجد header باسم Authorization (إلا في MERCHANT). أو رفضت Shukah الـ token، أو الـ token ليس بين tokens المخزَّنة. أو أي استثناء أثناء فحص الـ token. أو auth_source هو locate والـ token هو JWT من Locate.
422{"status":422,"message":"Your application is not support"}Authorization موجود، لكن x-auth-from مفقود أو ليس من القيم الخمس.
404{"status":404,"message":"User not found"}مع x-auth-from: LOCATE_V2 فقط، عندما يكون المستخدم القديم (legacy) مفقودًا.
500{"status":500,"message":"Internal server errors"}يُلقي الـ handler استثناءً، أو يفشل الـ upstream الخاص بـ MERCHANT بأي شيء غير 401.

التُقط body الخاص بـ 401 على dev في 2026-10-01 دون token. والتُقط body الخاص بـ 422 Your application is not support على dev في 2026-10-02، مع JWT من Locate ودون x-auth-from. وأما الأجسام الأخرى فمن الشيفرة.

جرّبه​

export AUTH_BASE_URL=https://dev.authentication.locate.sa
export SHUKAH_TOKEN='<shukah-token>' # a Locate JWT is expected to get 401 here on dev today (inference); see Feature
curl -s "$AUTH_BASE_URL/api/v1/users" -H "Authorization: Bearer $SHUKAH_TOKEN" -H "x-auth-from: SHUKAH"

المتوقع على dev (2026-10-02، استنتاج: لم يُستدعَ هذا الـ route مع x-auth-from في ذلك اليوم، بل استُدعيت routes النقاط التي تستدعيه): 200 والملف الشخصي المبيّن تحت «الاستجابة» لـ token من Shukah، و401 لـ JWT من Locate، إذ يمرّره dev إلى Shukah التي لم تعد تقبله. وفي 2026-10-01 حصل الـ token كلاهما على 200. وبدون x-auth-from تحصل على 422 المبيّن تحت «الأخطاء».

تنبيه​

  • يُتوقَّع أن يحصل JWT من Locate على 401 هنا على dev اليوم (استنتاج من routes النقاط، 2026-10-02)، وفي الشيفرة المثبَّتة يحدث ذلك دائمًا عندما يكون auth_source هو locate، فلا تَعِد بدعم JWT من Locate على هذا الـ route.
  • x-auth-from حساس لحالة الأحرف: SHUKAH يعمل، وshukah يحصل على 422. وإحدى وثائق الخدمة تكتبه بأحرف صغيرة.
  • في وضع التمرير (relay) يذهب كل استدعاء إلى Shukah أيضًا ويحدّث سجل مستخدم قديم (legacy)، ولا يعمل JWT من Locate إلا إذا كانت Shukah تعرفه.

التفاصيل (للـ backend)​

فُحص dev فقط: الـ host https://dev.authentication.locate.sa والبادئة /api/v1. أما الـ host والبادئة في UAT وproduction: غير موثّق بعد.

المستدعون​

  • خدمة النقاط: يحتاج clientAuthMiddleware إلى Authorization: Bearer <token>، ثم يستدعي GET {AUTH_SERVICE_URL}/api/v1/users بذلك الـ header، مع ضبط x-auth-from على AUTH_VERIFY_APPLICATION (الافتراضي SHUKAH) وAccept: application/json. والإجابة غير 2xx تصبح 401. ومعرّف العميل هو أول قيمة غير null من client_id وuser_id وid في الإجابة، ويجب أن يكون عددًا صحيحًا موجبًا. ولا يُمرَّر x-auth-from الخاص بالمستدعي أبدًا.
  • order-v2: يجري UserProfileGuard الاستدعاء نفسه بالـ header Authorization الذي استلمه وx-auth-from: SHUKAH. ويُطبَّق بـ @UseGuards(UserProfileGuard) على كثير من controllers العميل، مثل الطلبات وبطاقات الهدايا.

قيم x-auth-from الخمس​

ترتيب الفحوص: MERCHANT أولًا، ثم غياب Authorization (401)، ثم قيمة x-auth-from (422)، ثم switch. والمقارنة حساسة لحالة الأحرف (src/middlewares/user.js:13-44، src/shared/constant/auth.js:1-7).

x-auth-fromما يحدثbody النجاحالمصدر
SHUKAHيُفحص الـ token كما في الجدول التالي.الملف الشخصي.src/middlewares/user.js:36-37,100-187
LOCATE_V2 (الحالة الافتراضية في الـ switch)يُبحث عن الـ token في مجموعة users القديمة (legacy). والمستخدم القديم بحالة DEACTIVATE يعطي 401. ثم يُرجع الـ handler وثيقة المستخدم المخزَّنة، أو 404.وثيقة المستخدم القديم.src/middlewares/user.js:42-43,201-228؛ src/controllers/users/detail/handler.js:26-36
ADMIN_SHUKAHيجب أن يساوي الـ token token المسؤول المضبوط، وإلا 401.200 فارغ.src/middlewares/user.js:38-39,189-199؛ src/controllers/users/detail/handler.js:15-17
ADMIN_LOCATEGET {LOCATE_GO_BASE_URL}/api/admin/api/v1/profile مع Bearer token. وأي فشل يعطي 401.الملف الشخصي من الـ upstream.src/middlewares/user.js:40-41,250-275
MERCHANTيحتاج الـ headers access-token وclient وuid. وغياب أحدها يعطي 422 {"status":422,"message":"Unauthorization"}. ثم GET {MERCHANT_BASE_URL}/api/v1/users/profile. و401 من الـ upstream يعطي 401، وغيرها من حالات الفشل تعطي 500.الملف الشخصي من الـ upstream.src/middlewares/user.js:54-98
مفقودة أو أي قيمة أخرى، مع وجود Authorization422 {"status":422,"message":"Your application is not support"}.—src/middlewares/user.js:28-33؛ src/shared/constant/error-message.js:62

كيف يفحص SHUKAH الـ token​

auth_sourceJWT من Locate (ثلاثة أجزاء تفصلها نقاط تمامًا)token معتم (Opaque)المصدر
locateيستدعي verifyClientToken الدالة ClientService.findByToken، فتُلقي TypeError: Client.findByToken(...).cacheQuery is not a function. فالدالة static في النموذج هي async، فتُرجع Promise، وليس للـ Promise cacheQuery. ويحوّلها الـ catch إلى 401، في كل مرة. فحص دون اتصال بـ JWT صالح والـ middleware الحقيقي.يجد صف token_bridge نشطًا بحسب الـ token الخام، ثم العميل. وعدم العثور عليه يعطي 401. والعثور عليه يضبط الملف الشخصي من toShukahClientProfile (أنواع خام).src/middlewares/user.js:104-130,230-248؛ src/services/client.js:12-35؛ src/models/client.js:163-175
أي قيمة أخرى (عادةً shukah)تمرير (Relay): GET {SHUKAH_HOST}/maeda/api/verify-token مع Authorization: Bearer <token>. و200 مع body يصبح الملف الشخصي، كما أرسلته Shukah. وأي فشل يعطي 401.التمرير نفسه.src/middlewares/user.js:132-186

تحسم getAuthSource() القيمة بهذا الترتيب: متغير البيئة AUTH_SOURCE، ثم auth_source المخزَّن مؤقتًا في مفتاح settings:client في Redis، ثم GET {LOCATE_API_URL}/settings/client، ثم القيمة الافتراضية locate (src/services/setting.js:12-51، docs/plans/2026-08-25-point-ledger-shared-write-contract.md:408-421). وتحدّث رسالة Kafka من locate-go الـ cache (src/events/settingConsumer.js:14-33، docs/plans/2026-07-28-settings-broker-consumer.md:43-68).

  • لا يفحص أي من فرعَي locate حالة الحساب. فـ ClientService.findOne يرشّح بـ client_id فقط، وClient.findByToken يرشّح بـ is_deleted: false وهاتف الـ token فقط. لذا لا يفرض هذا الـ route شرط «النشط فقط» كما يفعل الـ middleware المسمّى client (قراءة شيفرة، src/services/client.js:5-17، src/models/client.js:163-175).
  • في فرع التمرير (relay) يكتب كل استدعاء في مجموعة users القديمة: عملية upsert من حمولة Shukah. فالحقل status بالقيمة active يصبح ACTIVE، وأي قيمة أخرى DEACTIVATE، وsex بقيمة 0 يصبح MALE، وأي قيمة أخرى FEMALE. وقاعدة sex هذه تختلف عن ترميز الملف الشخصي نفسه (1 ذكر، 2 أنثى) (src/middlewares/user.js:145-172).
  • يقبل التمرير JWT من Locate فقط إذا كانت Shukah تعرفه. وهذا يعتمد على دفع JWTs الجديدة من Locate إلى Shukah (انظر استبدال الـ token)، لذا فالعميل الذي فشل دفعه أو تُخطّي (لا معرّف له في Shukah) سيحصل على 401 هنا ما دام auth_source هو shukah (قراءة شيفرة).
  • التوقيت على dev: 630 ms لـ token من Shukah و1061 ms لـ JWT من Locate، مقابل 161 إلى 331 ms للاستدعاءات التي تبقى داخل الخدمة. وهذا يتسق مع قفزة (hop) إلى upstream.

ما لا تفسّره الالتقاطتان​

أعاد الاستدعاءان الملتقطان body بتنسيق Shukah (status بأحرف صغيرة، وsex عدد صحيح، وأعلام 0 و1) وكانا بطيئين. وفي الشيفرة المثبَّتة لا يستطيع إنتاج هذا الـ body لـ JWT من Locate سوى فرع التمرير. فإما أن auth_source على dev لم يكن locate في 2026-10-01، وقبلت Shukah الـ JWT من Locate (وهذا يتسق مع كون استدعاء exchange-token الذي أنشأه قد دفعه إلى Shukah، إن كان الدفع مفعّلًا على dev)، وإما أن dev لا يشغّل 6757aa4. ولا الشيفرة ولا الوثائق تقول أيهما: غير موثّق بعد. وهذا استنتاج، لا حقيقة.

للتمييز بينهما، قارن مدة تشغيل العملية (uptime) من route /health غير المصادَق (دون بادئة) مع دمج 6757aa4 في 2026-10-01 11:57 +0700، واقرأ auth_source من إعدادات العميل (src/routes/health.js:8، src/controllers/health/handler.js:11-19).

أُجيب عنه في 2026-10-02. أعادت إعدادات العميل العامة (GET https://dev.go.locate.sa/api/v1/settings/client، وهو الـ host في SETTINGS_BASE_URL بالتطبيق) القيمة "auth_source":"shukah". وقد يتجاوزها متغير البيئة AUTH_SOURCE ولا يمكن قراءته من الخارج، فهذا مرجَّح جدًّا وليس مثبتًا. ومدة التشغيل في /health وهي 90,815 s تعني أن الخدمة بدأت نحو 2026-10-01 06:43 UTC، أي بعد دمج 6757aa4 (04:57 UTC) بساعة و46 دقيقة، فالأرجح أن dev يشغّل 6757aa4 أو ما بعده. فالتفسير الأول هو الأرجح: ففي 2026-10-01 عمل فرع الـ relay وقبلت Shukah على dev الـ JWT من Locate. وفي 2026-10-02 رفضه الـ relay نفسه، ولهذا تعطي routes النقاط في order-v2 لـ JWT من Locate 401 Invalid or expired token (locate-point-service: services/api/src/services/client-auth.service.ts:17,22-29). ولماذا توقفت Shukah على dev عن قبول الـ JWT: غير موثّق بعد. والسبب المرجَّح أن دفع الـ token من Locate إلى Shukah (src/config/envConfig.js:22-35) لم يصل، أو لم يعد موجودًا في نسخة Laravel من Shukah على dev (استنتاج).

وعيب locate + JWT موجود أيضًا في origin/production عند 4f3bc96 (2026-09-21)، الذي يملك src/services/client.js وsrc/models/client.js نفسيهما كما في 6757aa4. وهل يعمل أي شيء من ذلك الـ ref، وهل يُخطَّط لإصلاح قبل أن ينقلب auth_source: غير موثّق بعد.

حيث تختلف الوثائق عن الشيفرة (القول للشيفرة)​

  • تكتب وثيقة تصميم قيمة الـ header بالشكل x-auth-from: shukah (docs/plans/2026-08-25-point-ledger-shared-write-contract.md:418). أما الشيفرة فتقارن بـ SHUKAH تمامًا، والقيمة بأحرف صغيرة تحصل على 422.
  • تقول وثيقة تصميم إن JWTs من Locate "short-circuit to verifyClientToken … and were never broken" (docs/plans/2026-07-27-shukah-opaque-token-auth-fix.md:51-52). وكان ذلك صحيحًا في 2026-07-27 وصار قديمًا منذ commit 3396fd1 (2026-07-28): فمع ضبط auth_source على locate، يعطي فرع JWT دائمًا 401.
  • 2026-10-02: قالت هذه الصفحة إن token من Shukah وJWT من Locate حصلا كلاهما على 200 على dev (2026-10-01)، وإن «جرّبه» فيها يتوقع 200 لأي من الـ token. وفي 2026-10-02 كان auth_source على dev هو shukah ولم تعد Shukah على dev تقبل الـ JWT من Locate، فلا يعمل إلا token من Shukah؛ ومع ضبط auth_source على locate يحصل كل JWT على 401 لأن src/services/client.js:12-17 يستدعي .cacheQuery على الـ Promise الذي تُرجعه Client.findByToken من نوع async (src/models/client.js:163).

Sources​

  • locate-authentication-service@6757aa4: src/routes/user.js:5-12, src/middlewares/user.js:13-275، src/controllers/users/detail/handler.js:9-45, src/services/client.js:5-35، src/models/client.js:163-175, src/services/setting.js:12-51، src/events/settingConsumer.js:14-33, src/shared/constant/auth.js:1-7، src/shared/constant/error-message.js:59,62,77, src/routes/health.js:8، src/controllers/health/handler.js:11-19
  • وثائق locate-authentication-service@6757aa4: docs/plans/2026-08-25-point-ledger-shared-write-contract.md:408-421، docs/plans/2026-07-28-settings-broker-consumer.md:43-68، docs/plans/2026-07-27-shukah-opaque-token-auth-fix.md:51-52
  • locate-point-service@2c44ce3: services/api/src/middleware/client-auth.ts:7-18، services/api/src/services/client-auth.service.ts:15-37
  • locate-order-v2-api@d9e4e5f6: src/auth/guards/user-profile-auth.guard.ts:58-72، src/modules/client/orders/orders.controller.ts:84، src/modules/client/gift-card-code/gift-card-code.controller.ts:10، src/modules/client/point/point.controller.ts:17-45 (ليس لـ routes النقاط حارس وهي تمرّر Authorization إلى خدمة النقاط)
  • نسخة الجوال اللحظية mobile/locate-client@e960c3a (الفرع development، 2026-02-26؛ شيفرة التطبيق نفسه، وليست من Locate): البحث في الشجرة كاملة عن api/v1/users لا يجد شيئًا
  • locate-authentication-service@6757aa4: src/config/envConfig.js:22-35
  • التقاطات dev، 2026-10-02 (parity audit): user-detail--locate-jwt وpoints--locate-jwt و points--locate-st؛ وإعدادات العميل على dev ومدة تشغيل /health لخدمة المصادقة، وكلتاهما قُرئتا في 2026-10-02
  • التقاطات dev، 2026-10-01: locate-users-shukah-token وlocate-users-locate-token و probe-locate-users وshukah-verify-token