快速開始
這是一份五分鐘、保管模式的走查。你的後端發出三支 HTTP 呼叫,最後其中一位 end user 的 SD-JWT 憑證會被存進 TCS Holder Service。完全不需要錢包 App,也不需要在你這端簽 JWT。
還沒選好模式?先看保管模式 vs 非保管模式。
Step 0:先設定後續 curl 範例會用到的環境變數
Section titled “Step 0:先設定後續 curl 範例會用到的環境變數”請在同一個 shell 執行以下命令一次,後面三個 curl 才能照範例直接執行。佔位字串請以 sandbox 或正式環境的實際值取代。
export ISSUER_API_KEY="tcs_xxxxxxxxxxxxxxxxxxxxxxxx"export HOLDER_USER_ACCESS_TOKEN="eyJhbGciOiJ...你的 holder login JWT..."export HOLDER_PRIVATE_KEY_BASE64URL="POST /v1/did 取得之 base64url 編碼私鑰"export HOLDER_DID="did:iota:testnet:0x5678..."export ISSUER_BASE="https://issuer.turingspace.co"export HOLDER_BASE="https://holder.turingspace.co"Step 1:你的後端建立 credential offer
Section titled “Step 1:你的後端建立 credential offer”用你的 Issuer API key 對 Credential Issuer 打:發行端只需要這一支呼叫。
curl -X POST "${ISSUER_BASE}/v1/offers" \ -H "Content-Type: application/json" \ -H "X-API-Key: ${ISSUER_API_KEY}" \ -d '{ "credential": { "config_id": "TuringCerts_Standard_Credential_v2_sd_jwt", "claims": { "credentialName": "Employee Badge", "issuedTime": "2026-04-01T00:00:00Z" } }, "flow": "pre-authorized", "expires_in": 3600 }'config_id 是你租戶的 issuer metadata credential_configurations_supported map 中的 key —— 透過 GET /.well-known/openid-credential-issuer/{tenant} 探索 sandbox 內可用的值。Sandbox 租戶預載 TuringCerts_Standard_Credential_v2_sd_jwt;其他類型請見 Schema Registry 目錄。
回應:
{ "offer_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "credential_offer_uri": "https://issuer.turingspace.co/v1/offers/a1b2c3d4-...", "deep_link": "openid-credential-offer://?credential_offer_uri=...", "expires_at": "2026-04-01T01:00:00Z"}非保管模式下,你會把 deep_link 用 QR 給 user 的錢包 App。保管模式下,把 deep_link(openid-credential-offer:// 形式)當作 credential_offer_uri 在下一步交給 Holder Service。
Step 2:你的後端請 Holder Service 收下憑證
Section titled “Step 2:你的後端請 Holder Service 收下憑證”用該位 end user 的 access token(不是 Issuer API key)打 Holder Service,把 offer URI 連同該位 user 的 DID 與私鑰一起傳。Holder Service 會在內部處理掉 wallet 端所有 protocol 工作 — pre-auth code 交換、proof JWT、DPoP。
curl -X POST "${HOLDER_BASE}/v1/oid4vci/receive" \ -H "Authorization: Bearer ${HOLDER_USER_ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "credential_offer_uri": "openid-credential-offer://?credential_offer_uri=https%3A%2F%2Fissuer.turingspace.co%2Fv1%2Foffers%2Fa1b2c3d4-...", "holder_did": "did:iota:testnet:0x5678...", "private_key": "${HOLDER_PRIVATE_KEY_BASE64URL}", "notarize_on_iota": true }'回應(201 Created):
{ "credential_id": "f7e8d9c0-1b2a-3c4d-5e6f-7a8b9c0d1e2f", "vct": "https://schema-registry.turingspace.co/schemas/TuringCerts_Standard_Credential/v2", "issuer_did": "did:iota:testnet:0xabcdef...", "holder_did": "did:iota:testnet:0x5678...", "raw_credential": "eyJhbGciOiJFZERTQSIs...~sd_disclosure_1~sd_disclosure_2~", "issued_at": "2026-04-01T00:00:30Z", "status": "active"}憑證已經放進該位 end user 在 Holder Service 的儲存裡。
上方範例顯式帶了 notarize_on_iota: true。簽出來的 SD-JWT 憑證會同時錨定到 IOTA Tangle,在離線 SD-JWT 之外多一份公開、長期可查的稽核紀錄。若不需要鏈上錨點(純 SD-JWT),改成 notarize_on_iota: false。省略此欄位時平台預設為 true,仍建議顯式帶值以確保升級後行為穩定。完整路徑、簽章方法限制與如何驗證鏈上紀錄請見 On-chain notarization。其他 optional 欄位:credential_configuration_id(offer 帶多個 configuration 時挑一個)、user_pin(僅當 issuer 設 require_transaction_code: true 才需要)。完整說明見Holder · 管理錢包與憑證 § 2。
Step 3:列出該 user 的憑證確認結果
Section titled “Step 3:列出該 user 的憑證確認結果”curl "${HOLDER_BASE}/v1/vc" \ -H "Authorization: Bearer ${HOLDER_USER_ACCESS_TOKEN}"可以看到 Step 2 發的那張憑證。之後同一位 user 要出示給 verifier 時,打 POST /v1/oid4vp/presentation。
驗證整合是否正確
Section titled “驗證整合是否正確”下列三個具體斷言確認整合端到端可用。可以放進你的測試套件或 CI smoke check:
- Step 1 —
POST /v1/offers回201,credential_offer_uri非空,expires_at為未來時間。 - Step 2 —
POST /v1/oid4vci/receive回201,status: "active",raw_credential為非空字串且以eyJ開頭(SD-JWT VC 之 base64 JWS header)。 - Step 3 —
GET /v1/vc回傳{ "credentials": [...] },內含一筆id等於 Step 2 的credential_id,且status: "active"。(List 端點的欄位名稱是id;credential_id只出現在 receive 回應上。)
若任一斷言失敗,最常見原因:config_id 不正確(Step 1 → 400)、offer URI 過期或重用(Step 2 → 400)、access_token 錯誤(Step 2/3 → 401,需重呼叫 POST /v1/user/login)。
- 包含驗證的完整流程 → Holder · 管理錢包與憑證
- 客製 offer(PIN、authorization code flow、schema-bound claims) → Issuer · 發行憑證
- 設置 verifier 端 → Verifier · 驗證憑證
- 跳過 Holder Service(用外部錢包) → 非保管模式