把簽署,
接回你的服務。
免註冊、免 API 金鑰,直接整合。把文件交給 Proof 簽署,再安全地接回你的流程。每次以新的非對稱金鑰證明 Session 控制權,不需向 Proof 登記身分或交換共用密鑰。
三種入口,一套協定
三種入口共用同一套 Session、金鑰、文件與 receipt 模型。
- 準備文件與金鑰
固定 PDF bytes、SHA-256;產生全新的 ownership、transport key 與 bootstrap capability。
- 建立 Session
簽署 request → Proof 驗簽;上傳加密 PDF。Proof 不取得解密 capability。
- 選擇入口
網站跳轉 / 原生 App handoff / 桌機 QR;同一個 App Clip ceremony。
- 確認與簽署
解密並核對文件 hash → 閱讀確認 → NFC + PIN → 卡片簽署。
- 交付已簽文件
加密並上傳固定的 signed artifact。網路重試不重新簽署。
- 回到 requester 驗證
同機返回 / 桌機 polling;ownership proof 取結果,驗 artifact、PAdES 與 Proof receipt。
- 繼續原工作流程
持久化已驗證結果 → ACK → 清理短期金鑰。
同機網站・架構時序,非正式上線狀態。左右滑動可查看完整圖表。
原生 iOS App・架構時序,非正式上線狀態。左右滑動可查看完整圖表。
桌機 QR・架構時序,非正式上線狀態。左右滑動可查看完整圖表。
返回只負責導覽,不代表簽署成功。只有驗證 artifact 與 Proof-signed receipt 後,requester 才能推進 workflow。Bootstrap 用於文件解密與 transport binding,不具 Session ownership 權限。
先接上流程,再深入協定。
SDK 封裝 Session 建立、端對端加密、結果解密、簽章及收據驗證。瀏覽器使用 IndexedDB 保存接續資料;Worker 使用 SealedRecoveryStore 加密保存金鑰。
套件名稱:@sentry-security/proof-sdk@0.2.1,發布於 GitHub Packages。私有套件下載需要套件存取權;這與 Proof API 不需帳號或 API Key 的整合模型不同。可下載本頁原始碼範例自行建置。
import { SigningSessionClient } from '@sentry-security/proof-sdk';
import { BrowserRecoveryStore } from '@sentry-security/proof-sdk/recovery-store';
const client = new SigningSessionClient({
storage: new BrowserRecoveryStore(),
});
const session = await client.create(file, {
context: 'web',
returnURL: location.origin + '/sign/return',
});
// 交給點擊連結或 QR 的 UI;不要記錄或公開此網址。
showSigningLink(session.invocationURL);
// 返回頁面或輪詢時,以保存的 session_id 接續。
const saved = await client.recover(session.session.session_id);
const result = await client.complete(saved);
// complete() 可能仍回傳等待狀態;僅完成並驗證後推進業務。
if (result.status === 'COMPLETED') {
// 另依業務規則核對預期簽署者,並保存文件與收據。
acceptVerifiedResult(result);
}協定參考:建立簽署要求
協定採 Ed25519、RFC 8785 JCS、compact JWS、RFC 7638 thumbprint。請使用成熟套件,不要用一般 JSON.stringify 當 canonicalization。Web 與 Cloudflare Workers 共用 requester SDK。下方保留協定位元組範例;日常整合可由 SDK 處理加密、驗證與復原。
import { createOwnership, signCreate, random256 } from './sdk/src/ownership.mjs';
import { invitationKeyPair, bootstrapCommitment } from './sdk/src/bootstrap.mjs';
// 每次 Session 產生新 key;私鑰只留在 requester。
const owner = await createOwnership();
const invitation = await invitationKeyPair();
const request = {
protocol: 'sentry-proof-signing/1',
request_id: crypto.randomUUID(), nonce: random256(),
iat: now, exp: now + 600,
bootstrap_commitment: await bootstrapCommitment(invitation),
document: { display_name: '測試合約.pdf', sha256: originalHash },
credential: { type: 'MOICA' },
document_transport: transportDeclaration,
return: { type: 'web', url: 'https://example.com/sign/return' }
};
const response = await fetch('https://proof.sentry.red/v1/signing-sessions', {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(await signCreate(request, owner))
});
// 此段展示請求格式;now、originalHash、transportDeclaration 由發起方準備。完整流程請使用上方 SDK 或下載範例。API 與權限
| 路徑 | 用途/授權 |
|---|---|
POST /v1/signing-sessions | 整份 create request 的 ownership JWS |
GET /v1/signing-sessions/{id}/challenge | 短效單次 challenge,指定 action |
PUT /v1/signing-sessions/{id}/source | X-Proof-Ownership 綁 ciphertext hash;body 是密文 |
POST /v1/signing-sessions/{id}/result | get-result ownership proof,取得狀態/metadata/receipt |
POST /v1/signing-sessions/{id}/artifact | get-artifact ownership proof,取得已簽密文 |
POST /v1/signing-sessions/{id}/confirm | confirm-artifact proof 綁 confirmation body hash |
POST /v1/signing-sessions/{id}/acknowledge | acknowledge proof 綁 receipt hash acknowledgement |
GET /.well-known/jwks.json | Proof receipt 公鑰;依 kid 驗證 |
驗證結果,才能繼續 workflow
拿到 session_id 或跳回 return URL,都不是成功證明。先驗 bootstrap-authenticated pairing record、解密與核對已簽 PDF hash,再以 requester 的 PAdES 政策驗章。取得 receipt 後,核對固定的 Proof JWKS、alg、typ、kid 以及 session_id、request_id、nonce、request_key_thumbprint、bootstrap_commitment、原始與已簽文件 hash。
Receipt 將證據分為 proof/requester/ceremony 來源。Requester 回報的 PAdES 結果,不等於 Proof 獨立檢查過 PDF。符合憑證簽署不代表符合你的預期簽署人授權,這仍由業務端判斷。
原生 iOS 與返回
原生 App 與 Web、桌機 QR 使用同一套 Session。Swift requester 實作涵蓋請求組裝、加密上傳、結果回收與收據核對;可參考專案內的 RequesterSessionClient 與 RequesterRecovery。返回採 HTTPS universal link,僅負責導覽。#sp2 以精簡 envelope 交付 bootstrap capability;整合時應測試你的瀏覽器、通訊軟體及 App 是否完整保留連結。缺少 capability 時中止,不改放 query 或傳至 Proof。
重試與金鑰生命週期
- 同一 signed create 重送回同一 Session;不要修改 request 後重用 nonce 或 key。
- Ownership challenge 60 秒、單次使用;重試操作要取得新 challenge。
- 卡片簽完後重試同一份 artifact;不要因網路失敗重新簽出另一份 PDF。
- Return 只喚醒 requester;驗證、持久化完成與 ACK 後才刪除 requester key。
- V1 使用 authenticated polling,沒有任意 callback 或 webhook secret。
安全邊界與測試建議
QR 洩漏可能讓取得者解密文件及進入 ceremony,但不能取得 requester ownership。請測試錯誤 key、文件被修改、challenge replay、重複上傳、網路中斷、返回頁面與 full App 路由。請勿記錄完整 request、文件 URL token、PIN 或 private key。
前往可操作的整合體驗 ↗