Tổng quan API — GIW POC Identity Platform

Trạng thái: POC · Phiên bản: 0.1.0 · Ngày: 21/09/2026 Đặc tả: openapi.yaml (OpenAPI 3.0.3, đã validate)


1. Nền tảng này chứng minh điều gì

Bốn điều, chạy trọn luồng, trên một máy tính xách tay:

  1. Khách hàng đăng ký, đăng nhập và đăng xuất với Keycloak, nhận về một phiên OIDC.
  2. Cán bộ nhân viên được xác thực bằng mã nhân viên + CCCD, trong đó Keycloak — không phải portal — gọi HR Verification API và chỉ cấp phiên khi MATCH + ACTIVE.
  3. Sau cả hai đường, Wi-Fi Portal lấy quyết định từ Entitlement Service, rồi mới yêu cầu Session Service mở truy cập.
  4. CCCD không bao giờ lọt vào token, log, bản ghi cơ sở dữ liệu hay thông báo lỗi.

2. Kiến trúc API — portal làm chủ giao diện

Không có trang nào do Keycloak render trong nền tảng này. Wi-Fi Portal tự phục vụ màn hình của nó và gọi Galaxy ID qua token API và admin API.

Browser ──▶ Portal API ──┬──▶ Galaxy ID (Keycloak)   xác thực
   (sid cookie)          ├──▶ Entitlement Service    quyết định
                         └──▶ Session Service        thực thi
                                     │
                      Keycloak ──────┴──▶ HR Verification API

Trình duyệt chỉ nói chuyện với đúng một host — portal — và giữ đúng một cookie mờ. Nó không bao giờ thấy token, không biết địa chỉ Keycloak, cũng không biết địa chỉ của bất kỳ hệ thống phía sau nào.

Vì sao không dùng luồng redirect

Authorization Code redirect là câu trả lời trong sách giáo khoa, và ở đây nó sai:

  • Captive network assistant (trình duyệt mini mà iOS và macOS bật lên trên Wi-Fi captive) xử lý redirect sang origin bên thứ ba rất tệ và không giữ cookie đáng tin. Đăng nhập kiểu redirect hỏng đúng ở nơi sản phẩm này sống.
  • Tính liền mạch thương hiệu: đẩy hành khách Vietjet sang một trang Keycloak rồi quay lại là một vết nối nhìn thấy được trong hành trình 30 giây.

Cái giá phải trả, nói thẳng

Mất gì Hệ quả
SSO giữa các sản phẩm Galaxy Mỗi lần đăng nhập portal là độc lập
MFA / step-up Không có cách chuẩn nào để thử thách thêm bên trong password grant
Liên kết IdP (doanh nghiệp, mạng xã hội) Sẽ phải thêm lại một đường redirect
Thông tin đăng nhập không đi qua portal Portal giờ nằm trong phạm vi audit về xử lý credential

Đây không phải là một mẫu được khuyến nghị. RFC 9700 (OAuth 2.0 Security Best Current Practice) nói password grant MUST NOT be used, và không ghi nhận ngoại lệ first-party nào. Direct Grant chỉ được dùng như một giải pháp tạm thời có giới hạn cho POC, nhằm kiểm chứng trải nghiệm captive portal. Kiến trúc xác thực cho production vẫn TBC và nên ưu tiên OIDC/federation chạy trên trình duyệt khi điều kiện vận hành cho phép.

Những gì không thay đổi, và không được phép thay đổi:

  • Keycloak vẫn ra mọi quyết định xác thực. Portal không có kho mật khẩu, không có credential của HR.
  • Keycloak vẫn gọi HR để xác minh nhân viên, qua một direct-grant authenticator tuỳ biến. Portal chỉ chuyển tiếp hai ô trên form.
  • Token nằm lại phía server.

Chuẩn sẵn có và phần Galaxy tự xây

Chặng Bản chất Đặc tả ở đâu
Browser ↔ Wi-Fi Portal Galaxy tự xây openapi.yaml → /api/v1/auth/*
Wi-Fi Portal ↔ Galaxy ID CHUẨN OAuth 2.0 / OIDC — RFC 6749 §4.3 password grant, RFC 6749 §4.4 client credentials, RFC 7009 logout, Keycloak Admin REST Discovery document của Keycloak. Không đặc tả lại trong openapi.yaml.
Keycloak ↔ HR Verification API Galaxy tự xây openapi.yaml → POST /api/v1/employees/verify
Wi-Fi Portal ↔ Entitlement Service Galaxy tự xây openapi.yaml → POST /api/v1/entitlements/evaluate
Wi-Fi Portal ↔ Session Service Galaxy tự xây openapi.yaml → /api/v1/sessions*

Các endpoint chuẩn đang dùng, chỉ để tham chiếu:

Mục đích Endpoint (realm galaxy-id-poc) Client
Đăng nhập khách hàng POST /protocol/openid-connect/token grant_type=password wifi-portal-api
Xác minh nhân viên POST /protocol/openid-connect/token grant_type=password + employeeId + citizenId wifi-portal-employee-api
Refresh POST /protocol/openid-connect/token grant_type=refresh_token cả hai
Service token (đăng ký) POST /protocol/openid-connect/token grant_type=client_credentials wifi-portal-api
Tạo tài khoản POST /admin/realms/{realm}/users service account, chỉ manage-users
Back-channel logout POST /protocol/openid-connect/logout cả hai
JWKS GET /protocol/openid-connect/certs Entitlement Service

Luồng nhân viên không có endpoint riêng. Nó vẫn là token endpoint thông thường, trên một confidential client thứ hai mà flow direct_grant bị ghi đè thành employee-direct-grant. Authenticator của Keycloak đọc employeeId và citizenId từ request rồi gọi HR.

3. Phân tách trách nhiệm

Keycloak            danh tính và xác thực              BẠN LÀ AI
HR Verification     tình trạng lao động                CÓ PHẢI NHÂN VIÊN, CÒN LÀM VIỆC KHÔNG
Entitlement         quyết định quyền truy cập          ĐƯỢC DÙNG GÌ
Session / Network   thực thi quyền truy cập            BẬT LÊN

Hai quy tắc rút ra, và cả hai được cưỡng chế bằng code chứ không chỉ bằng văn bản:

  • Keycloak không bao giờ mở mạng. Nó phát token rồi dừng. Portal phải tự đi lấy entitlement.
  • Session Service không bao giờ quyết định. POST /sessions/{id}/grant trả 422 ENTITLEMENT_DENIED nếu không có entitlementId (ADR-008).

4. Các thành phần

Service Cổng Công nghệ Vai trò
keycloak 8080 (9000 health) Keycloak 26.7.4 + custom Java SPI Galaxy ID. Có cả browser flow lẫn direct-grant flow cho nhân viên
postgres-keycloak — Postgres 16 Lưu trữ cho Keycloak
mock-hr-api 3001 Node 22, không dependency Đóng vai hệ thống nhân sự gốc
entitlement-service 3002 Node 22, không dependency Verify token, áp policy, cấp entitlement
session-service 3003 Node 22, không dependency Mô phỏng các động từ của Network Adapter theo ADR-007
wifi-portal 3000 Node 22, không dependency Phục vụ giao diện, gọi Galaxy ID, điều phối entitlement và session
bootstrap — Node 22 Chạy một lần: client scope, flow binding, user test

Các service Node không có dependency npm nào, có chủ đích. Một POC xử lý CCCD thì phải đọc kiểm được từng dòng, không phải lần theo một cây dependency bắc cầu.

5. Liên kết danh tính — chiến lược cho POC

Khi một nhân viên xác thực, authenticator tuỳ biến tìm user Keycloak theo thứ tự này:

  1. User mang attribute employee_ref bằng đúng reference mà HR trả về.
  2. Nếu không có, user có username là reference viết thường (emp-12345).
  3. Nếu vẫn không có, tạo user mới.

Nếu bước 1 tìm thấy nhiều hơn một user cùng employee_ref, luồng thất bại với IDENTITY_LINK_CONFLICT thay vì đoán.

Cố ý không làm: tự động gộp với một tài khoản CUSTOMER đã có, khớp theo email hoặc số điện thoại. Gộp hai danh tính một cách im lặng là việc không thể hoàn tác, và là quyết định cho production chứ không phải tiện tay trong POC. Theo dõi ở T-LINK §8.

Production: TBC. Cần quyết định Galaxy ID giữ một subject với hai vai trò, hay hai subject liên kết nhau. Liên quan ADR-002.

6. Correlation

Mọi request đều mang hoặc tự sinh X-Correlation-ID, và nó được trả lại trên mọi response. Một id đi suốt:

Portal → Keycloak → Custom Authenticator → HR API → Entitlement → Session

Sinh theo dạng corr-<uuid4>. Nó không bao giờ được dẫn xuất từ CCCD, mã nhân viên hay bất kỳ dữ liệu cá nhân nào — một correlation id sẽ nằm trong log và dashboard, đó là thiết kế.

7. Giả định của POC

Mọi thứ trong bảng này là phỏng đoán đặt ra để dựng được stack. Không có gì là SLA production.

Giả định Giá trị Đặt ở đâu
Timeout gọi HR verify 3000 ms GIW_HR_TIMEOUT_MS
Số lần gọi HR 2 (một lần thử lại) GIW_HR_MAX_ATTEMPTS
TTL entitlement nhân viên 4 h TTL_EMPLOYEE_SEC
TTL entitlement khách hàng 1 h TTL_CUSTOMER_SEC
Vòng đời access token 900 s cấu hình realm
Timeout Portal → Galaxy ID 5000 ms idp.js
Timeout Portal → Galaxy ID, luồng nhân viên 12000 ms IDP_EMPLOYEE_TIMEOUT_MS. Phải lớn hơn hrTimeoutMs × hrMaxAttempts, nếu không portal hết giờ trước và đổ lỗi cho Galaxy ID về một sự cố của HR.
TTL phiên portal 3600 s, dọn mỗi 5 phút server.js
SSO idle / max 1800 s / 36000 s cấu hình realm
Số lần submit form mỗi phiên xác thực 5 cấu hình authenticator
Giới hạn tần suất gọi HR 30 req / 60 s mỗi peer RATE_LIMIT_MAX
Công ty đủ điều kiện VIETJET, GALAXY, SOVICO EMPLOYEE_COMPANIES

8. Câu hỏi còn mở

Ref Câu hỏi Chặn cái gì
T-CCCD CCCD có được chấp nhận làm đầu vào xác minh cho production hay không? ADR-003 và quyết định D3 hiện nói bỏ nó đi; POC này vẫn làm vì task order yêu cầu. Luồng nhân viên production
T-LINK Một subject hai vai trò, hay hai subject liên kết, khi một nhân viên đồng thời là khách hàng? ADR-002, mô hình user
T-TIER BASIC/BOOST có phải là hạng thật không, và đòn bẩy là thời lượng hay tốc độ? ADR-011, danh mục entitlement
T-HR-SOR Hệ thống nào mới là hệ nhân sự gốc thật, và hợp đồng, mô hình xác thực, SLA thực tế của nó là gì? Toàn bộ chặng Keycloak ↔ HR
T-AUD Mỗi service có nên có audience riêng thay vì chấp nhận account không? API-SECURITY.md §3
T-GRANT Password grant có chấp nhận được lâu dài không, hay portal nên chuyển sang device/CIBA flow, hoặc thêm một đường redirect cho federation doanh nghiệp? §2 ở trên, ADR-002
T-MFA Nếu sau này bắt buộc MFA, password grant không mang được step-up. Thay bằng gì? §2 ở trên
T-STORE Trạng thái entitlement và session đang nằm trong bộ nhớ. Kho lưu trữ production là gì và giữ bao lâu? DATA-CLASSIFICATION.md

9. Thứ tự đọc cho người review

  1. Tài liệu này
  2. API-MATRIX.md — mọi thứ trên một trang
  3. API-SEQUENCES.md — ba luồng dưới dạng sơ đồ
  4. TOKEN-CLAIMS.md — hợp đồng token
  5. DATA-CLASSIFICATION.md — từng trường dữ liệu sống ở đâu và chết ở đâu
  6. API-SECURITY.md — các biện pháp, và những gì còn thiếu
  7. ERROR-CATALOG.md
  8. API-REVIEW-CHECKLIST.md — mang phản biện của bạn tới đây

GIW POC Identity Platform · bản demo local · không phải production · sinh từ repository