Sơ đồ tuần tự API — GIW POC Identity Platform

Trạng thái: POC · Ngày: 21/09/2026

Mọi luồng đều là lệnh gọi API. Trình duyệt không bao giờ rời portal và không bao giờ thấy một trang Keycloak nào. Số thứ tự các bước tương ứng với những dòng log mà bạn theo dõi được bằng một X-Correlation-ID duy nhất.


1. Đăng nhập khách hàng

sequenceDiagram
    autonumber
    actor U as Hành khách
    participant B as Frontend portal
    participant P as Portal API
    participant K as Galaxy ID (Keycloak)
    participant E as Entitlement Service
    participant S as Session Service

    U->>B: mở captive portal
    B->>P: GET /api/v1/auth/session
    P-->>B: authenticated false
    B-->>U: màn hình vào, 3 nút

    U->>B: Đăng nhập Galaxy ID, gửi form
    B->>P: POST /api/v1/auth/login {username, password}

    P->>K: POST /token grant_type=password<br/>(confidential client + secret)
    Note over P,K: Portal không có kho mật khẩu.<br/>Keycloak quyết định, không phải portal.
    K-->>P: access_token, refresh_token, id_token

    P->>E: POST /entitlements/evaluate (Bearer, Idempotency-Key)
    E->>K: GET /certs (JWKS, cache 5 phút)
    E->>E: verify chữ ký, iss, aud, exp rồi áp policy
    E-->>P: 201 WIFI_CUSTOMER_BASIC · tier BASIC

    P->>S: POST /sessions (Idempotency-Key)
    S-->>P: 201 state CREATED
    P->>S: POST /sessions/{id}/grant (entitlementId)
    S-->>P: 200 state GRANTED

    P-->>B: 200 + Set-Cookie sid (mờ, HttpOnly, SameSite=Strict)
    Note over B: Token nằm lại phía server.<br/>Trình duyệt chỉ giữ cookie.
    B-->>U: màn hình Access Granted

Luôn luôn entitlement trước, session sau. Một session tạo ra trước khi có quyết định là một session có thể bị grant do vô tình.


2. Đăng ký

sequenceDiagram
    autonumber
    actor U as Hành khách
    participant B as Frontend portal
    participant P as Portal API
    participant K as Galaxy ID (Keycloak)

    U->>B: Đăng ký Galaxy ID
    B->>P: POST /api/v1/auth/register {email, password, displayName}
    P->>P: kiểm định dạng email, độ dài mật khẩu
    Note over P: Bị từ chối ở đây nghĩa là<br/>Galaxy ID không bị làm phiền.

    P->>K: POST /token grant_type=client_credentials
    K-->>P: token của service account
    Note over P,K: Service account giới hạn ở manage-users.<br/>Cố ý không phải realm-admin.

    P->>K: POST /admin/realms/{realm}/users
    alt tạo thành công
        K-->>P: 201
        P->>K: POST /token grant_type=password
        K-->>P: tokens
        Note over P: Đăng ký rồi đăng nhập: đúng một<br/>đường code sinh ra phiên.
        P-->>B: 200 (entitlement + session, như luồng 1)
    else đã tồn tại
        K-->>P: 409
        P-->>B: 409 ACCOUNT_EXISTS
    end

3. Xác minh cán bộ nhân viên

sequenceDiagram
    autonumber
    actor U as Nhân viên
    participant B as Frontend portal
    participant P as Portal API
    participant K as Galaxy ID (Keycloak)
    participant A as Direct-grant authenticator
    participant H as HR Verification API
    participant E as Entitlement Service
    participant S as Session Service

    U->>B: Đăng nhập CBNV
    B-->>U: form do portal render (mã NV + CCCD)
    U->>B: gửi form
    B->>P: POST /api/v1/auth/employee {employeeId, citizenId}
    P->>P: chỉ kiểm có mặt hay không

    P->>K: POST /token grant_type=password<br/>+ employeeId + citizenId
    Note over P,K: CCCD đi như một trường riêng,<br/>không bao giờ là tham số password của OAuth.

    K->>A: direct_grant flow = employee-direct-grant
    A->>A: kiểm định dạng
    A->>H: POST /employees/verify (X-API-Key, X-Correlation-ID)
    H->>H: so sánh thời gian hằng số trên mọi bản ghi
    H-->>A: verified, active, EMP-12345, VIETJET, eligible
    Note over A: citizenId ra khỏi scope tại đây.<br/>Không lưu, không log, không vào token.

    A->>K: tìm hoặc tạo user theo employee_ref
    A->>K: đặt user_type, employee_verified, employee_ref, company
    K-->>P: token kèm claim của nhân viên

    P->>E: POST /entitlements/evaluate
    E-->>P: 201 WIFI_EMPLOYEE_PACKAGE · BOOST · 2 thiết bị
    P->>S: POST /sessions rồi /grant
    S-->>P: 200 GRANTED
    P-->>B: 200 + Set-Cookie sid
    B-->>U: Access Granted

Portal là bộ chuyển tiếp, không phải bên ra quyết định. Nó không giữ credential nào của HR và có muốn cũng không xác minh được ai.


4. Đăng xuất

sequenceDiagram
    autonumber
    actor U as Hành khách
    participant P as Portal API
    participant S as Session Service
    participant K as Galaxy ID

    U->>P: POST /api/v1/auth/logout (cookie sid)
    P->>S: POST /sessions/{id}/revoke
    S-->>P: 200 REVOKED
    Note over P,S: Thu hồi trước. Nếu lệnh gọi IdP<br/>sau đó hỏng thì truy cập đã tắt rồi.
    P->>K: POST /logout (back-channel, refresh_token)
    P->>P: bỏ phiên phía server
    P-->>U: 200 + xoá cookie sid

5. Các luồng hỏng

5a. HR hết giờ hoặc sập

sequenceDiagram
    autonumber
    participant P as Portal API
    participant K as Galaxy ID
    participant A as Direct-grant authenticator
    participant H as HR Verification API

    P->>K: POST /token (+ employeeId, citizenId)
    K->>A: employee-direct-grant
    A->>H: lần 1 (timeout 3000 ms)
    H--xA: không phản hồi
    Note over A: Thử lại an toàn — verify là chỉ đọc.
    A->>H: lần 2
    H--xA: không phản hồi
    A-->>K: 504 temporarily_unavailable
    K-->>P: 504
    P-->>P: ánh xạ thành HR_SERVICE_TIMEOUT
    Note over P: Không session. Không tạo user.<br/>Không cấp một phần.

Ngân sách thời gian của chính portal cho lệnh gọi này là 12 s, cố ý lớn hơn 3000 ms × 2 lần. Đặt thấp hơn thì portal hết giờ trước và báo "Galaxy ID đang sập" trong khi lỗi thật nằm ở HR — đội hỗ trợ sẽ đi truy sai hệ thống.

Một 401/403 từ HR thì không thử lại: credential service sai sẽ không tự sửa, và nó hiện ra là "tạm thời không truy cập được" chứ không tiết lộ rằng khoá đã bị từ chối.

5b. Sai thông tin đăng nhập, không có tài khoản, hoặc tài khoản đang bị khoá

sequenceDiagram
    autonumber
    participant B as Frontend portal
    participant P as Portal API
    participant K as Galaxy ID

    B->>P: POST /api/v1/auth/login
    P->>K: POST /token grant_type=password
    alt sai mật khẩu
        K-->>P: 401 invalid_grant
    else không có tài khoản
        K-->>P: 401 invalid_grant
    else đang bị khoá do brute-force
        K-->>P: 401 invalid_grant
    end
    P-->>B: 401 INVALID_CREDENTIALS<br/>"Thông tin đăng nhập không đúng."
    Note over K,B: Ba nguyên nhân khác nhau, một câu trả lời y hệt.<br/>Khác đi là tạo ra một kênh dò tài khoản.

5c. Nhân viên: không tìm thấy, sai CCCD, nghỉ việc, không đủ điều kiện

sequenceDiagram
    autonumber
    participant P as Portal API
    participant A as Direct-grant authenticator
    participant H as HR Verification API

    P->>A: employeeId + citizenId
    A->>H: POST /employees/verify
    H->>H: quét mọi bản ghi, thời gian hằng số, khối lượng việc đều nhau

    alt không khớp (không có mã HOẶC sai CCCD)
        H-->>A: verified false, NOT_FOUND_OR_MISMATCH
        A-->>P: 401 invalid_grant → INVALID_CREDENTIALS
        Note over H,P: Một câu trả lời y hệt cho cả hai.<br/>Cũng không có tín hiệu về thời gian.
    else khớp nhưng INACTIVE
        H-->>A: verified true, active false
        A-->>P: 403 employee_inactive → EMPLOYEE_INACTIVE
        Note over A,P: Chỉ tới được đây sau khi CCCD ĐÚNG,<br/>nên nói rõ lý do không làm lộ gì.
    else khớp, ACTIVE, nhưng không đủ điều kiện wifi
        H-->>A: wifiEligible false
        A-->>P: 403 access_denied → FORBIDDEN
    end

5d. Xác thực được nhưng không đủ điều kiện

sequenceDiagram
    autonumber
    participant P as Portal API
    participant K as Galaxy ID
    participant E as Entitlement Service
    participant S as Session Service

    P->>K: POST /token (+ employeeId, citizenId)
    K-->>P: token — HR xác nhận nhân viên ACTIVE, đủ điều kiện
    P->>E: POST /entitlements/evaluate (company PARTNER-X)
    E->>E: PARTNER-X không nằm trong EMPLOYEE_COMPANIES
    E-->>P: 403 ENTITLEMENT_DENIED · COMPANY_NOT_ELIGIBLE
    P-->>P: không tạo session nào cả
    Note over P,S: Xác thực đã thành công.<br/>Truy cập thì không.<br/>Đây là hai câu hỏi khác nhau.

Đây là luồng đáng trình bày với người bảo trợ dự án. Trường hợp test: PTX10001 / 001234500005.

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