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 tin | Mô tả |
|---|---|
| Access ID | Mộ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 Key | Secret key dùng để ký mọi request và xác minh signature của mọi response. Do CAKE cung cấp. |
| Base URL | Do CAKE cấp cùng bộ credentials, cho cả môi trường stage và production. |
| Mobile SDK | CICReader 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ường | Kiểu | Mô tả |
|---|---|---|
NOT_VERIFIED | string | Giao 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. |
VERIFIED | string | Dữ liệu chip đã được đọc và xác nhận với C06. |
EXPIRED | string | Giao 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 tin | Mô tả |
|---|---|
| Tạo giao dịch | Backend của bạn mở một giao dịch và nhận JWT mà SDK sẽ dùng. |
| Đọc NFC | SDK 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 NFC | Backend của bạn xác minh lần đọc với C06 và đóng giao dịch. |
| Lấy dữ liệu NFC | Truy 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 tin | Mô 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:
| Header | Mô tả |
|---|---|
X-TV-Timestamp | Timestamp hiện tại theo định dạng RFC3339. Ví dụ: 2019-04-21T18:00:15+07:00 |
Authorization | ATV <ACCESS_ID>:<SIGNATURE> |
Signature là một HMAC-SHA256 mã hóa Base64 của một StringToSign chuẩn hóa:
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:
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ý:
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.
| Header | Mô tả |
|---|---|
X-Signature-Timestamp | Timestamp đã ký theo định dạng RFC3339. Ví dụ: 2019-04-21T18:00:15+07:00 |
X-Signature | Token HMAC mã hóa Base64 từ server CAKE. Ví dụ: <SIGNATURE> |
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
- Backend của bạn gọi
POST /v1/create_transactionvớidocument_idcủa công dân vàref_idriêng của bạn, được ký bằng HMAC. - eID trả về
idcủa giao dịch,statuslàNOT_VERIFIED, và mộttoken— JWT mà SDK sẽ dùng để xác thực. - 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
- 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,dg14vàdg15. - Ứng dụng gọi
POST /v1/read_nfcvới các data group đó, xác thực bằng bearer token. - 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_imagetừ DG2, và mộtverification_key. - Ứng dụng chuyển
verification_keyvề 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
- Backend của bạn gọi
POST /v1/verify_nfcvớidocument_id,ref_idvàverification_key, được ký bằng HMAC. - eID đối chiếu dữ liệu chip với cơ sở dữ liệu công an quốc gia C06.
- Response mang theo
is_verifiedvàverified_at, và giao dịch chuyển sangVERIFIED. Kết quả phía server này — chứ không phảiis_verifiedmà 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
POST /v1/get_nfctrả 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 đúngdocument_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.
{
"success": true,
"code": 0,
"message": "success",
"request_id": "133963a4-3d2c-4a85-b0a1-3fa2878b8f99",
"data": {}
}| Trường | Kiểu | Mô tả |
|---|---|---|
success | bool | Cuộc gọi có thành công hay không. |
code | int | Mã lỗi. 0 nghĩa là không có lỗi; phạm vi chạy tới 999999. |
message | string | Thông báo trạng thái. |
request_id | string | ID request của server, dùng để tracing. Độ dài tối đa 64. |
data | object | Payload 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ả |
|---|---|
2001002 | internal_bad_gateway |
2001010 | API key không đúng. |
2001019 | Không tìm thấy transaction / reference ID. |
2001020 | Lock giao dịch thất bại. |
2001021 | Request giao dịch không hợp lệ. |
2001022 | Giao dịch đã được xác minh. |
2001023 | Khóa giao dịch không hợp lệ. |
2001027 | Token không hợp lệ. |
2001029 | Không tìm thấy thông tin NFC. |
2001030 | Document ID không hợp lệ. |
4001000 | Tham số đầu vào vi phạm một ràng buộc. |
4291000 | Số lượng request vượt quá giới hạn throughput. |
5001000 | internal_server_error — xảy ra lỗi không mong đợi trong quá trình xử lý request. |
HTTP status codes
| Mã | Mô tả |
|---|---|
401 | Bạn không được phép thực hiện hành động này. |
500 | Xảy ra lỗi không mong đợi trong quá trình xử lý request. |
Bước tiếp theo
- Tạo giao dịch — mở một giao dịch và cấp token cho SDK
- Đọc NFC — gửi các data group của chip và nhận về thông tin định danh đã phân tích
- Xác minh NFC — xác nhận lần đọc với cơ sở dữ liệu C06
- Lấy dữ liệu NFC — truy xuất dữ liệu chip thô và đã phân tích được lưu trữ
- Định nghĩa các trường CCCD — mọi trường định danh, địa chỉ, cấp phát, QR và MRZ, cùng định dạng, quy tắc kiểm tra hợp lệ và gộp dữ liệu
- Mã lỗi — bảng lỗi đầy đủ trên cả API và Mobile SDK
- Tùy biến giao diện Android SDK — tùy biến giao diện màn hình quét của CICReader
- Lấy giao dịch — đọc trạng thái hiện tại của một giao dịch
- Xác minh khóa xác thực giao dịch — redeem key và đóng giao dịch