Skip to content

Tổng quan eID ​

eID là dịch vụ định danh đọc chip của CAKE: Mobile SDK đọc chip không tiếp xúc bên trong CCCD (Căn cước công dân gắn chip) của Việt Nam, nền tảng sẽ phân tích các data group theo chuẩn ICAO, trả về các trường thông tin định danh của chủ thẻ, và xác minh chúng với cơ sở dữ liệu công an quốc gia C06. Trang này trình bày vòng đời giao dịch, hai phương thức xác thực, và luồng xử lý đầu-cuối.

INFO

Mọi ví dụ trong tài liệu này dùng cùng một danh tính giả định — Nguyễn Văn A, CCCD 001xxxxxxxxx, user_id user_00000001, ref_id ref_00000001. Thông tin xác thực, token và key được ghi dạng <PLACEHOLDER>. Đây không phải dữ liệu thật; hãy thay toàn bộ bằng giá trị của bạn.

Điều kiện tiên quyết ​

Trước khi gọi bất kỳ endpoint nào, bạn cần một tenant được CAKE cấp phát cùng bộ thông tin xác thực đi kèm.

Thông tinMô tả
Access IDMột UUID định danh duy nhất cho Tenant của bạn. Được gửi trong header Authorization. Do CAKE cung cấp.
Access KeySecret key dùng để ký mọi request và xác minh signature của mọi response. Do CAKE cung cấp.
Base URLDo CAKE cấp cùng bộ credentials, cho cả môi trường stage và production.
Mobile SDKCICReader SDK, được nhúng vào ứng dụng iOS hoặc Android của bạn, thực hiện thao tác đọc chip vật lý.
Thiết bị hỗ trợ NFCĐiện thoại của người dùng cuối phải có đầu đọc NFC và thẻ phải là CCCD có gắn chip.

Liên hệ CAKE Support để nhận access_id và access_key.

Các ví dụ trong tài liệu này ghi base URL dưới dạng <BASE_URL> — hãy thay bằng giá trị CAKE cấp cho bạn.

Vòng đời giao dịch ​

Mỗi lần đọc chip diễn ra bên trong một giao dịch (transaction), đi qua ba trạng thái.

TrườngKiểuMô tả
NOT_VERIFIEDstringGiao dịch đã được tạo và token đã được cấp, nhưng dữ liệu chip chưa được xác minh với C06.
VERIFIEDstringDữ liệu chip đã được đọc và xác nhận với C06.
EXPIREDstringGiao dịch không được hoàn tất trước khi token hết hạn.

Bốn endpoint đưa một giao dịch đi qua vòng đời đó:

Thông tinMô tả
Tạo giao dịchBackend của bạn mở một giao dịch và nhận JWT mà SDK sẽ dùng.
Đọc NFCSDK gửi các data group thô của chip và nhận về các trường thông tin định danh đã phân tích cùng một verification_key.
Xác minh NFCBackend của bạn xác minh lần đọc với C06 và đóng giao dịch.
Lấy dữ liệu NFCTruy xuất dữ liệu chip thô và đã phân tích được lưu trữ cho một document.

Xác thực ​

eID dùng hai phương thức, và phương thức nào bạn dùng phụ thuộc vào endpoint, không chỉ vào bên gọi.

Thông tinMô tả
HMAC — Authorization: ATV <ACCESS_ID>:<SIGNATURE>Được backend của bạn dùng cho Tạo giao dịch và Xác minh NFC.
JWT — Authorization: Bearer {token}Được Mobile SDK dùng cho Đọc NFC và Lấy dữ liệu NFC. Token đến từ Tạo giao dịch.

WARNING

Access Key là một bí mật phía server. Không bao giờ nhúng nó vào ứng dụng di động hay bất kỳ client nào do người dùng cuối kiểm soát — SDK được cấp một JWT riêng cho từng giao dịch chính là để khóa ký không bao giờ rời khỏi backend của bạn.

Phương án 1: Xác thực HMAC (backend đến NFC backend) ​

Các request server-to-server được xác thực bằng HMAC-SHA256, chứng minh cả tính toàn vẹn lẫn tính xác thực của nội dung request bằng một khóa dùng chung (shared secret) giữa backend của bạn và CAKE.

Hai header là bắt buộc:

HeaderMô tả
X-TV-TimestampTimestamp hiện tại theo định dạng RFC3339. Ví dụ: 2019-04-21T18:00:15+07:00
AuthorizationATV <ACCESS_ID>:<SIGNATURE>

Signature là một HMAC-SHA256 mã hóa Base64 của một StringToSign chuẩn hóa:

text
StringToSign = HttpMethod + "\n" + UrlPath + "\n" + Timestamp + "\n" + HashedBody

# HttpMethod: POST, GET, PUT, PATCH hoặc DELETE
# UrlPath:    đường dẫn route tương đối, không gồm domain. Ví dụ: /v1/create_transaction
# Timestamp:  thời điểm request theo định dạng RFC3339; phải khớp với header X-TV-Timestamp
# HashedBody: hex_encode(SHA256(raw body))
#             Ví dụ (body `{}`): 44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a

Signature = Base64(HmacSha256(AccessKeySecret, Utf8EncodingOf(StringToSign)))

Cách triển khai tham chiếu bằng JavaScript:

javascript
const CryptoJS = require("crypto-js");

const timestamp = new Date().toISOString(); // 2024-05-09T07:53:10.591Z
const access_key = "<ACCESS_KEY>";
const path = "/v1/create_transaction";
const body = `{
    "document_id": "001xxxxxxxxx",
    "ref_id": "ref_00000001"
}`;

function tokenize(method, path, timestamp, body, key) {
  const hashed_body = CryptoJS.SHA256(body).toString(CryptoJS.enc.Hex);
  const formatted = `${method}\n${path}\n${timestamp}\n${hashed_body}`;
  const hmac = CryptoJS.HmacSHA256(formatted, key);
  const hashed = hmac.toString(CryptoJS.enc.Hex);
  return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Hex.parse(hashed));
}

const authorize_token = tokenize("POST", path, timestamp, body, access_key);
// Gửi `timestamp` làm X-TV-Timestamp và `authorize_token` làm signature — không bao giờ ghi log.

Ví dụ request đã ký:

bash
curl --location '<BASE_URL>/v1/create_transaction' \
  --header 'Authorization: ATV <ACCESS_ID>:<SIGNATURE>' \
  --header 'X-TV-Timestamp: <TIMESTAMP>' \
  --header 'Content-Type: application/json' \
  --header 'X-Request-Id: <RANDOM_UUID>' \
  --header 'X-Client-ID: <CLIENT_ID>' \
  --data '{
    "document_id": "001xxxxxxxxx",
    "ref_id": "ref_00000001"
}'

INFO

StringToSign dùng SHA256 của raw body mã hóa dạng hex. Một số tenant của CAKE được cấp phát dùng hash body mã hóa Base64 thay thế — hãy xác nhận với đội CAKE tenant của bạn đang dùng biến thể nào trước khi triển khai.

Phương án 2: JWT token (Mobile SDK đến NFC backend) ​

Tạo giao dịch trả về một JWT token giới hạn phạm vi trong một giao dịch, một user và một ref_id. SDK trình nó dưới dạng bearer token, và nó ngừng hoạt động ngay khi hết hạn.

Xem token là chuỗi mờ (opaque): chuyển nguyên trạng cho SDK, không parse, không ghi log, không lưu trữ.

Ký response ​

Mọi response từ NFC backend đều được ký bằng HMAC-SHA256 trên method, path, timestamp và hash của response body, để backend của bạn có thể chứng minh payload thực sự đến từ CAKE.

HeaderMô tả
X-Signature-TimestampTimestamp đã ký theo định dạng RFC3339. Ví dụ: 2019-04-21T18:00:15+07:00
X-SignatureToken HMAC mã hóa Base64 từ server CAKE. Ví dụ: <SIGNATURE>
text
StringToSign = HttpMethod + "\n" + UrlPath + "\n" + Timestamp + "\n" + HashedBody

# HttpMethod: method của API đã được gọi
# UrlPath:    đường dẫn route tương đối, không gồm domain
# Timestamp:  thời điểm ký theo định dạng RFC3339, được gửi trong X-Signature-Timestamp
# HashedBody: hex_encode(SHA256(raw response body))

Signature = Base64(HmacSha256(AccessKeySecret, Utf8EncodingOf(StringToSign)))

WARNING

Hãy tính lại và so sánh X-Signature trước khi tin tưởng is_verified. Một response chưa được xác minh là một response chưa được xác thực, và kết quả C06 chính là căn cứ cho quyết định onboarding của bạn.

Cách hoạt động ​

Một phiên NFC đầy đủ trải qua bốn actor: ứng dụng di động có nhúng SDK, backend của bạn, backend eID, và cơ sở dữ liệu công an quốc gia C06.

sequenceDiagram
    autonumber
    participant App as Mobile App / SDK
    participant BE as Backend của bạn
    participant NFC as eID Backend
    participant C06 as Cơ sở dữ liệu C06

    Note over BE,NFC: Giai đoạn 1 — Mở giao dịch
    BE->>NFC: POST /v1/create_transaction (ký HMAC)
    NFC-->>BE: id, status NOT_VERIFIED, token (JWT)
    BE-->>App: token

    Note over App,NFC: Giai đoạn 2 — Đọc chip
    App->>App: Người dùng chạm CCCD; SDK đọc SOD, DG1, DG2, DG13, DG14, DG15
    App->>NFC: POST /v1/read_nfc (Bearer token)
    NFC-->>App: các trường thông tin công dân, face_image, verification_key
    App-->>BE: verification_key

    Note over BE,C06: Giai đoạn 3 — Xác minh với C06
    BE->>NFC: POST /v1/verify_nfc (ký HMAC)
    NFC->>C06: Đối chiếu dữ liệu chip
    C06-->>NFC: Kết quả đối chiếu
    NFC-->>BE: is_verified, verified_at; status VERIFIED

    Note over BE,NFC: Giai đoạn 4 — Lấy dữ liệu đã lưu
    BE->>NFC: POST /v1/get_nfc
    NFC-->>BE: nfc_raw (data group) + nfc_data (trường đã phân tích)

Giai đoạn 1 — Mở giao dịch ​

  1. Backend của bạn gọi POST /v1/create_transaction với document_id của công dân và ref_id riêng của bạn, được ký bằng HMAC.
  2. eID trả về id của giao dịch, status là NOT_VERIFIED, và một token — JWT mà SDK sẽ dùng để xác thực.
  3. Backend của bạn chuyển token xuống ứng dụng di động. Nó không bao giờ chuyển Access Key.

Giai đoạn 2 — Đọc chip ​

  1. Người dùng chạm CCCD vào điện thoại. SDK thực hiện thao tác đọc chip theo chuẩn ICAO và trích xuất các data group: sod, dg1, dg2, dg13, dg14 và dg15.
  2. Ứng dụng gọi POST /v1/read_nfc với các data group đó, xác thực bằng bearer token.
  3. eID phân tích các data group và trả về các trường thông tin định danh của chủ thẻ, face_image từ DG2, và một verification_key.
  4. Ứng dụng chuyển verification_key về cho backend của bạn. Key này chính là thứ giúp backend của bạn chứng minh lần đọc đã thực sự diễn ra, mà không cần tin vào bất kỳ tuyên bố nào của ứng dụng về việc đó.

Giai đoạn 3 — Xác minh với C06 ​

  1. Backend của bạn gọi POST /v1/verify_nfc với document_id, ref_id và verification_key, được ký bằng HMAC.
  2. eID đối chiếu dữ liệu chip với cơ sở dữ liệu công an quốc gia C06.
  3. Response mang theo is_verified và verified_at, và giao dịch chuyển sang VERIFIED. Kết quả phía server này — chứ không phải is_verified mà SDK thấy được ở bước 6 — mới là kết quả logic quyết định của bạn nên dùng.

Giai đoạn 4 — Truy xuất dữ liệu đã lưu ​

  1. POST /v1/get_nfc trả về cả nfc_raw (các data group gốc) và nfc_data (các trường thông tin định danh đã phân tích) cho đúng document_id đã gửi trong cùng giao dịch.

Cấu trúc response dùng chung ​

Mọi endpoint đều trả về cùng một cấu trúc bên ngoài.

json
{
  "success": true,
  "code": 0,
  "message": "success",
  "request_id": "133963a4-3d2c-4a85-b0a1-3fa2878b8f99",
  "data": {}
}
TrườngKiểuMô tả
successboolCuộc gọi có thành công hay không.
codeintMã lỗi. 0 nghĩa là không có lỗi; phạm vi chạy tới 999999.
messagestringThông báo trạng thái.
request_idstringID request của server, dùng để tracing. Độ dài tối đa 64.
dataobjectPayload riêng của từng endpoint.

Lưu ý request_id nằm ở cấp cao nhất (top level) trên các endpoint của eID, không nằm bên trong data như trên các API ảnh của eKYC.

Mã lỗi thường gặp ​

MãMô tả
2001002internal_bad_gateway
2001010API key không đúng.
2001019Không tìm thấy transaction / reference ID.
2001020Lock giao dịch thất bại.
2001021Request giao dịch không hợp lệ.
2001022Giao dịch đã được xác minh.
2001023Khóa giao dịch không hợp lệ.
2001027Token không hợp lệ.
2001029Không tìm thấy thông tin NFC.
2001030Document ID không hợp lệ.
4001000Tham số đầu vào vi phạm một ràng buộc.
4291000Số lượng request vượt quá giới hạn throughput.
5001000internal_server_error — xảy ra lỗi không mong đợi trong quá trình xử lý request.

HTTP status codes ​

MãMô tả
401Bạn không được phép thực hiện hành động này.
500Xảy ra lỗi không mong đợi trong quá trình xử lý request.

Bước tiếp theo ​

Developers