User detail
Bối cảnh
GET /api/v1/users là route "token này của ai?" tổng quát của auth service. Nó được viết từ trước khi
migrate, và không API Shukah nào ánh xạ tới nó. Với x-auth-from: SHUKAH nó kiểm tra một token và trả về
hồ sơ của client.
Nó quan trọng với việc migrate vì các backend khác dùng nó. order-v2 và point service gọi nó để biến token nhận được thành một client. Token đó có thể là token Shukah hoặc JWT của Locate, nên route này quyết định các route point của order-v2 chấp nhận token nào.
Tính năng
Gửi token trong Authorization và nói backend nào verify nó trong x-auth-from. Các caller
gửi SHUKAH.
- order-v2: profile guard của nó, bảo vệ nhiều route client như orders và gift cards, gọi
route này với
x-auth-from: SHUKAH. - Point service: client middleware của nó gọi route này để biết người gọi là ai. Nó gửi
x-auth-fromtừ settingAUTH_VERIFY_APPLICATIONcủa chính nó (mặc địnhSHUKAH), đọc client id từ câu trả lời, và trả401cho caller của nó khi route này không trả lời bằng2xx. - Các caller khác: Chưa được tài liệu hóa.
Bản thân app không gọi route này: snapshot app ngày 2026-02-26 không có lời gọi nào tới nó. App
không cần gửi x-auth-from tới các route point của order-v2, vì order-v2 và point
service tự set nó khi gọi route này.
Token nào chạy được phụ thuộc vào client setting auth_source (shukah hoặc locate), do locate-go
sở hữu. Nếu service không đọc được setting, nó dùng locate.
| Token | auth_source không phải locate | auth_source là locate |
|---|---|---|
| Token Shukah | Chạy được. Service nhờ Shukah kiểm tra (GET /maeda/api/verify-token) và trả nguyên câu trả lời của Shukah. | Chạy được khi token là một trong các token active đã lưu của service. Chưa capture. |
| JWT của Locate | Chỉ chạy nếu Shukah biết JWT đó, vì service vẫn hỏi Shukah. | Không bao giờ chạy ở code đã ghim: luôn nhận 401. Đây là một defect. |
Trên dev, vào 2026-10-01, một token Shukah và một JWT Locate đều nhận 200 với cùng body. Vào
2026-10-02 điều đó đã đổi. auth_source của dev là shukah (đọc từ client settings công khai), nên
route này chuyển tiếp token sang Shukah dev. Các route point của order-v2, vốn gọi route này, trả 401 cho
một JWT Locate và 200 cho một token Shukah: Shukah dev không còn chấp nhận JWT (đây là suy luận; bản thân
route này không được gọi với x-auth-from vào ngày đó). Nếu auth_source đặt là locate thì JWT cũng
sẽ fail, vì defect trong bảng. Vậy trên dev hiện nay chỉ có token Shukah chạy ở đây,
và không có setting nào một mình làm JWT Locate chạy được.
GET /api/v1/users
Request
| Field | Vị trí | Kiểu | Bắt buộc | Ràng buộc | Mô tả |
|---|---|---|---|---|---|
Authorization | header | string | có, trừ MERCHANT | Bearer <token>. Phần thứ hai (ngăn cách bằng dấu cách) là token. Thiếu cho 401. | Token cần kiểm tra. Trên dev hiện nay chỉ token Shukah qua được (2026-10-02). |
x-auth-from | header | string | có | Một trong SHUKAH, LOCATE_V2, ADMIN_SHUKAH, ADMIN_LOCATE hoặc MERCHANT. Phân biệt hoa thường: khi có Authorization, shukah cho 422. Các caller dùng SHUKAH, và phần còn lại của trang này nói về nó. | Backend nào verify token. |
access-token, client, uid | header | string | chỉ MERCHANT | Cả ba đều bắt buộc với MERCHANT. | Một phiên merchant. |
Response
Với x-auth-from: SHUKAH, 200 kèm hồ sơ của client là một object trần. Body phụ thuộc vào cách
service kiểm tra token:
| Cách kiểm tra token | Body |
|---|---|
Relay: auth_source không phải locate. | Body verify-token của chính Shukah, không đổi. Trên dev nó có cùng 13 field như Verify token: status là active, sex là 0, 1 hoặc 2, và các flag là 0 hoặc 1. |
Local, token Shukah: auth_source là locate. | Một shape khác: status là ACTIVE thô, sex là MALE, FEMALE hoặc UNKNOWN, bốn flag là boolean, và odoo_id bị bỏ khi client không có. Chưa capture. |
Local, JWT Locate: auth_source là locate. | Không thành công: 401 mọi lần ở code đã ghim. |
{
"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
}
Capture trên dev, 2026-10-01 (client 356259), một lần với token Shukah và một lần với JWT Locate: cả hai lời gọi trả body này. Các field cá nhân đã được thay thế. Vào 2026-10-02 một JWT Locate nhận 401 từ các route point gọi route này, nên body này là thứ một token Shukah nhận hiện nay.
Lỗi
| HTTP | Body | Khi nào |
|---|---|---|
401 | {"status":401,"message":"Unauthorization"} | Không có header Authorization (trừ MERCHANT). Shukah từ chối token, hoặc token không nằm trong các token đã lưu. Bất kỳ exception nào khi kiểm tra token. auth_source là locate và token là JWT Locate. |
422 | {"status":422,"message":"Your application is not support"} | Có Authorization, nhưng x-auth-from thiếu hoặc không phải một trong năm giá trị. |
404 | {"status":404,"message":"User not found"} | Chỉ với x-auth-from: LOCATE_V2, khi legacy user không tồn tại. |
500 | {"status":500,"message":"Internal server errors"} | Handler throw, hoặc upstream MERCHANT lỗi với bất cứ mã nào ngoài 401. |
Body 401 được capture trên dev vào 2026-10-01 khi không có token. Body 422
Your application is not support được capture trên dev vào 2026-10-02, với một JWT Locate và không có
x-auth-from. Các body còn lại lấy từ code.
Thử ngay
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"
Kỳ vọng trên dev (2026-10-02, suy luận: hôm đó route này không được gọi với x-auth-from, chỉ các
route điểm gọi tới nó được gọi): 200 và hồ sơ như ở mục Response với một token Shukah, và 401 với
một JWT Locate, vì dev chuyển tiếp nó sang Shukah, nơi không còn chấp nhận nó. Vào 2026-10-01 cả hai
token đều nhận 200. Không có x-auth-from bạn nhận 422 như ở mục Lỗi.
Lưu ý
- JWT Locate được dự đoán sẽ nhận
401ở đây trên dev hiện nay (suy luận từ các route điểm, 2026-10-02), và ở code đã ghim nó luôn như vậy khiauth_sourceđặt làlocate, nên đừng hứa hỗ trợ JWT Locate trên route này. x-auth-fromphân biệt hoa thường:SHUKAHchạy,shukahnhận422. Một tài liệu của service viết nó bằng chữ thường.- Ở chế độ relay mỗi lời gọi cũng đi tới Shukah và cập nhật một bản ghi legacy user, và JWT Locate chỉ chạy nếu Shukah biết nó.
Chi tiết (cho backend)
Chỉ kiểm tra dev: host https://dev.authentication.locate.sa, prefix /api/v1. Host và prefix của UAT
và production: Chưa được tài liệu hóa.
Các caller
- Point service:
clientAuthMiddlewarecầnAuthorization: Bearer <token>, rồi gọiGET {AUTH_SERVICE_URL}/api/v1/usersvới header đó,x-auth-fromđặt bằngAUTH_VERIFY_APPLICATION(mặc địnhSHUKAH) vàAccept: application/json. Câu trả lời không phải2xxthành401. Client id là giá trị non-null đầu tiên trongclient_id,user_idvàidcủa câu trả lời, và nó phải là số nguyên dương.x-auth-fromcủa chính caller không bao giờ được forward. - order-v2:
UserProfileGuardthực hiện cùng lời gọi với headerAuthorizationnó nhận được vàx-auth-from: SHUKAH. Nó được áp dụng bằng@UseGuards(UserProfileGuard)trên nhiều controller client, ví dụ orders và gift cards.
Năm giá trị x-auth-from
Thứ tự kiểm tra: MERCHANT trước, rồi Authorization thiếu (401), rồi giá trị của
x-auth-from (422), rồi một switch. Phép so sánh phân biệt hoa thường
(src/middlewares/user.js:13-44, src/shared/constant/auth.js:1-7).
x-auth-from | Điều gì xảy ra | Body thành công | Nguồn |
|---|---|---|---|
SHUKAH | Token được kiểm tra như ở bảng kế tiếp. | Hồ sơ. | src/middlewares/user.js:36-37,100-187 |
LOCATE_V2 (default case của switch) | Token được tra trong collection users legacy. Một user legacy DEACTIVATE cho 401. Sau đó handler trả document user đã lưu, hoặc 404. | Document legacy user. | src/middlewares/user.js:42-43,201-228; src/controllers/users/detail/handler.js:26-36 |
ADMIN_SHUKAH | Token phải bằng admin token đã cấu hình, nếu không 401. | Một 200 rỗng. | src/middlewares/user.js:38-39,189-199; src/controllers/users/detail/handler.js:15-17 |
ADMIN_LOCATE | GET {LOCATE_GO_BASE_URL}/api/admin/api/v1/profile với Bearer token. Mọi lỗi cho 401. | Hồ sơ từ upstream. | src/middlewares/user.js:40-41,250-275 |
MERCHANT | Cần các header access-token, client và uid. Thiếu một cái cho 422 {"status":422,"message":"Unauthorization"}. Sau đó GET {MERCHANT_BASE_URL}/api/v1/users/profile. Upstream 401 cho 401, các lỗi khác cho 500. | Hồ sơ từ upstream. | src/middlewares/user.js:54-98 |
Thiếu hoặc bất kỳ giá trị nào khác, khi có Authorization | 422 {"status":422,"message":"Your application is not support"}. | — | src/middlewares/user.js:28-33; src/shared/constant/error-message.js:62 |
SHUKAH kiểm tra token như thế nào
auth_source | JWT Locate (đúng ba phần ngăn cách bằng dấu chấm) | Token opaque | Nguồn |
|---|---|---|---|
locate | verifyClientToken gọi ClientService.findByToken, và nó throw TypeError: Client.findByToken(...).cacheQuery is not a function. Static của model là async, nên nó trả một Promise, và một Promise không có cacheQuery. Catch biến nó thành 401, mọi lần. Kiểm tra offline với một JWT hợp lệ và middleware thật. | Tìm một dòng token_bridge active theo token raw, rồi client. Không tìm thấy cho 401. Tìm thấy thì set hồ sơ từ toShukahClientProfile (kiểu raw). | src/middlewares/user.js:104-130,230-248; src/services/client.js:12-35; src/models/client.js:163-175 |
Bất kỳ giá trị nào khác (thường là shukah) | Relay: GET {SHUKAH_HOST}/maeda/api/verify-token với Authorization: Bearer <token>. Một 200 kèm body thành hồ sơ, đúng như Shukah gửi. Mọi lỗi cho 401. | Cùng relay đó. | src/middlewares/user.js:132-186 |
getAuthSource() resolve giá trị theo thứ tự: biến môi trường AUTH_SOURCE, rồi
auth_source đã cache của key settings:client trong Redis, rồi GET {LOCATE_API_URL}/settings/client,
rồi mặc định locate (src/services/setting.js:12-51,
docs/plans/2026-08-25-point-ledger-shared-write-contract.md:408-421). Một message Kafka từ locate-go
làm mới cache (src/events/settingConsumer.js:14-33,
docs/plans/2026-07-28-settings-broker-consumer.md:43-68).
- Cả hai nhánh
locateđều không kiểm tra trạng thái tài khoản.ClientService.findOnechỉ lọc theoclient_id, vàClient.findByTokenchỉ lọc theois_deleted: falsevà phone của token. Vì vậy route này không ép chỉ-active như middlewareclient(đọc code,src/services/client.js:5-17,src/models/client.js:163-175). - Ở nhánh relay mọi lời gọi đều ghi vào collection
userslegacy: một upsert từ payload của Shukah.statusactivethànhACTIVE, mọi giá trị khác thànhDEACTIVATE, vàsex0thànhMALE, mọi giá trị khác thànhFEMALE. Quy tắcsexđó khác với cách mã hóa của chính hồ sơ (1nam,2nữ) (src/middlewares/user.js:145-172). - Relay chỉ chấp nhận JWT Locate nếu Shukah biết nó. Điều đó phụ thuộc vào việc đẩy các JWT Locate mới
sang Shukah (xem Exchange token), nên một client mà push thất bại hoặc
bị bỏ qua (không có Shukah id) sẽ nhận
401ở đây khiauth_sourcelàshukah(đọc code). - Thời gian trên dev: 630 ms cho token Shukah và 1061 ms cho JWT Locate, so với 161 đến 331 ms cho các lời gọi nằm trong service. Điều đó khớp với một hop tới upstream.
Hai capture không giải thích được điều gì
Cả hai lời gọi đã capture đều trả body định dạng Shukah (status chữ thường, sex số nguyên, flag 0 và 1)
và đều chậm. Ở code đã ghim chỉ nhánh relay mới tạo ra body đó cho một JWT Locate. Vậy hoặc
auth_source của dev không phải locate vào 2026-10-01, và Shukah chấp nhận JWT Locate
(điều đó khớp với việc lời gọi exchange-token mint ra nó đã đẩy nó sang Shukah, nếu push được bật
trên dev), hoặc dev không chạy 6757aa4. Cả code lẫn tài liệu đều không nói là cái nào: Chưa được tài liệu
hóa. Đây là suy luận, không phải sự thật.
Để phân biệt, so sánh uptime của process từ route /health không cần xác thực (không có prefix)
với lần merge 6757aa4 lúc 2026-10-01 11:57 +0700, và đọc auth_source từ client settings
(src/routes/health.js:8, src/controllers/health/handler.js:11-19).
Đã có câu trả lời vào 2026-10-02. Client settings công khai
(GET https://dev.go.locate.sa/api/v1/settings/client, host nằm trong SETTINGS_BASE_URL của app)
trả "auth_source":"shukah". Một biến môi trường AUTH_SOURCE sẽ ghi đè nó và không thể
đọc từ bên ngoài, nên điều này rất có khả năng đúng, chưa được chứng minh. Uptime /health 90,815 s nghĩa là
service khởi động khoảng 2026-10-01 06:43 UTC, 1 giờ 46 phút sau lần merge 6757aa4 (04:57 UTC), nên dev
nhiều khả năng chạy 6757aa4 hoặc mới hơn. Vì vậy giải thích đầu tiên là giải thích có khả năng đúng: vào 2026-10-01
nhánh relay chạy và Shukah dev chấp nhận JWT Locate. Vào 2026-10-02 cùng relay đó từ chối nó, đó là lý do các
route point của order-v2 trả cho JWT Locate 401 Invalid or expired token
(locate-point-service: services/api/src/services/client-auth.service.ts:17,22-29). Vì sao Shukah dev
ngừng chấp nhận JWT: Chưa được tài liệu hóa. Nguyên nhân có khả năng là việc push token từ Locate sang Shukah
(src/config/envConfig.js:22-35) không tới được, hoặc không còn tồn tại trên bản port Laravel của Shukah dev
(suy luận).
Defect locate + JWT cũng có trong origin/production tại 4f3bc96 (2026-09-21), có
cùng src/services/client.js và src/models/client.js như 6757aa4. Có thứ gì chạy từ
ref đó hay không, và có kế hoạch sửa trước khi auth_source chuyển hay không: Chưa được tài liệu hóa.
Khi tài liệu và code mâu thuẫn (code thắng)
- Một design doc viết giá trị header là
x-auth-from: shukah(docs/plans/2026-08-25-point-ledger-shared-write-contract.md:418). Code so sánh vớiSHUKAHchính xác, và giá trị chữ thường nhận422. - Một design doc nói JWT Locate "short-circuit to
verifyClientToken… and were never broken" (docs/plans/2026-07-27-shukah-opaque-token-auth-fix.md:51-52). Điều đó đúng vào 2026-07-27 và đã lỗi thời từ commit3396fd1(2026-07-28): khiauth_sourceđặt làlocate, nhánh JWT luôn cho401. - 2026-10-02: trang này nói một token Shukah và một JWT Locate đều nhận
200trên dev (2026-10-01), và mục Thử ngay của nó kỳ vọng200với cả hai token. Vào 2026-10-02auth_sourcecủa dev làshukahvà Shukah dev không còn chấp nhận JWT Locate, nên chỉ token Shukah chạy; vớiauth_sourceđặt làlocatemọi JWT đều nhận401vìsrc/services/client.js:12-17gọi.cacheQuerytrên Promise doClient.findByTokenkiểuasynctrả về (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- Tài liệu của
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-37locate-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(các route point không có guard và forwardAuthorizationsang point service)- Snapshot mobile
mobile/locate-client@e960c3a(branchdevelopment, 2026-02-26; code của chính app, không phải Locate): tìm toàn bộ cây thư mục vớiapi/v1/userskhông thấy gì locate-authentication-service@6757aa4:src/config/envConfig.js:22-35- Capture dev, 2026-10-02 (parity audit):
user-detail--locate-jwt,points--locate-jwt,points--locate-st; client settings của dev và uptime/healthcủa auth service, cả hai được đọc vào 2026-10-02 - Capture dev, 2026-10-01:
locate-users-shukah-token,locate-users-locate-token,probe-locate-users,shukah-verify-token