跳到內容

快速開始

這是一份五分鐘、保管模式的走查。你的後端發出三支 HTTP 呼叫,最後其中一位 end user 的 SD-JWT 憑證會被存進 TCS Holder Service。完全不需要錢包 App,也不需要在你這端簽 JWT。

還沒選好模式?先看保管模式 vs 非保管模式


Step 0:先設定後續 curl 範例會用到的環境變數

Section titled “Step 0:先設定後續 curl 範例會用到的環境變數”

請在同一個 shell 執行以下命令一次,後面三個 curl 才能照範例直接執行。佔位字串請以 sandbox 或正式環境的實際值取代。

Terminal window
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 打:發行端只需要這一支呼叫。

Terminal window
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_linkopenid-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。

Terminal window
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 的憑證確認結果”
Terminal window
curl "${HOLDER_BASE}/v1/vc" \
-H "Authorization: Bearer ${HOLDER_USER_ACCESS_TOKEN}"

可以看到 Step 2 發的那張憑證。之後同一位 user 要出示給 verifier 時,打 POST /v1/oid4vp/presentation


下列三個具體斷言確認整合端到端可用。可以放進你的測試套件或 CI smoke check:

  1. Step 1 — POST /v1/offers201credential_offer_uri 非空,expires_at 為未來時間。
  2. Step 2 — POST /v1/oid4vci/receive201status: "active"raw_credential 為非空字串且以 eyJ 開頭(SD-JWT VC 之 base64 JWS header)。
  3. Step 3 — GET /v1/vc 回傳 { "credentials": [...] },內含一筆 id 等於 Step 2 的 credential_id,且 status: "active"。(List 端點的欄位名稱是 idcredential_id 只出現在 receive 回應上。)

若任一斷言失敗,最常見原因:config_id 不正確(Step 1 → 400)、offer URI 過期或重用(Step 2 → 400)、access_token 錯誤(Step 2/3 → 401,需重呼叫 POST /v1/user/login)。