【Agentic Payment 系列 #5】沒有人看到全貌:AP2 v0.2 用兩張 Mandate 重寫 Agent 的授權邊界
AP2 v0.2 把 Intent / Cart / Payment 三段式授權鏈重構為 Checkout 與 Payment 兩類 Mandate、各含 Open 與 Closed 兩階段。拆解新版的簽章綁定設計、Human Present 與 Human Not Present 的流程差異,以及以 SD-JWT 選擇性揭露構築的資訊隔離架構。
本文為 Agentic Payment 系列第五篇,直接延續第二篇對 AP2 授權機制的拆解: → 【Agentic Payment 系列 #2】信任的代價:AP2 授權機制、A2A 支付整合與三大協議戰場劃分
AP2 改版了。
我在前一篇介紹 AP2 的文章裡拆解的是 v0.1 的 Intent → Cart → Payment 三段式授權鏈:使用者簽 Intent、商家簽 Cart、憑證發行方簽 Payment,三張 Mandate 以雜湊值串成一條可審計的責任鏈。
2026 年 4 月 28 日,Google 在 GitHub 上發布 AP2 v0.2.0,同一天宣布將協議捐贈給 FIDO Alliance,交由新成立的 Agentic Authentication 與 Payments 兩個技術工作組接手標準化(FIDO Alliance 公告)。距離 v0.1.0 發布(2025/9/16)不到八個月。
Release note 上的官方對新版的定位:It focuses on providing Human Not Present flows. 但實際讀下來,這次改版不是把三個欄位擠成兩個那麼簡單,它換掉了整個授權模型的切分軸線。
v0.1 是用「流程階段」切的:先有意圖、再有購物車、最後有付款。v0.2 改用「授權邊界 vs. 實際成交」切。 這個調整影響了後面所有設計。
為什麼要改?
v0.1 的三段式有個結構性的尷尬:Cart Mandate 由商家簽,Payment Mandate 由憑證發行方簽,真正代表使用者意志的只有 Intent Mandate 一張。但在 Human-Not-Present(人類不在場)場景,使用者簽完 Intent 就離線了,後面兩張 Mandate 全是別人簽的。
於是「使用者授權的範圍」與「Agent 實際執行的內容」之間,隔著兩個第三方簽章。商家要驗證 Agent 有沒有超綱,得回頭去解析一份格式自由的意圖描述;銀行要判斷這筆錢是否在預算內,又得去翻另一張 Mandate。責任鏈是連著的,但驗證責任散落在各方,而且每一方驗的東西不一樣。
更麻煩的是 Prompt Playback。v0.1 用「把 Agent 的理解回放給使用者確認」來對抗 Hallucination,但那本質上是一段自然語言文字,人看得懂,機器沒辦法拿來做決定性的驗證。
v0.2 給出的答案是:不要讓機器去理解意圖,讓使用者把意圖直接簽成機器可驗證的約束條件。
v0.1 → v0.2 對照
先把兩版的差異攤開來看,後面的章節再逐項拆解:
| 面向 | v0.1(2025/9/16) | v0.2(2026/4/28) |
|---|---|---|
| Mandate 數量 | 三張(Intent / Cart / Payment) | 兩類 × 兩階段(Checkout / Payment,各有 Open 與 Closed) |
| 切分軸線 | 流程階段 | 授權邊界 vs. 實際成交 |
| 意圖表達 | Prompt Playback(自然語言回放) | Constraint 物件(機器可驗證) |
| 使用者簽幾次 | Intent 一次,Cart 視流程而定 | 一次確認、兩份 Mandate |
| Agent 綁定 | 無明確機制 | Open Mandate 以 cnf claim 綁定 agent_pk |
| 憑證格式 | VDC(未指定實作) | SD-JWT + 選擇性揭露 |
| 收據 | 流程尾端的通知 | 正式物件,防重複扣款的狀態機制 |
| 標準化歸屬 | Google 主導 | FIDO Alliance 技術工作組 |
Open 與 Closed:把「能做什麼」與「做了什麼」拆開
新版只有兩類 Mandate,但每一類各有 Open 與 Closed 兩個階段:
- Checkout Mandate:回答「買的東西有被授權嗎」,交給 Merchant(商家)驗證
- Payment Mandate:回答「這筆錢有被授權嗎」,交給 Credential Provider(憑證提供方)、Network(卡組織)與 MPP(Merchant Payment Processor,商家支付處理商)驗證

從左邊看起。使用者事先簽兩張 Open Mandate:Checkout Mandate 定義能跟誰買、買什麼、金額上限;Payment Mandate 定義能怎麼付、預算多少。這兩張不對應任何一筆具體交易,它們是授權的邊界。
這些邊界不是自然語言,而是規格定義好的 constraint 物件。Open Checkout Mandate 用 checkout.allowed_merchants 鎖商家白名單、checkout.line_items 鎖可接受的品項與數量;Open Payment Mandate 則有 payment.amount_range(單筆金額區間)、payment.budget(累計預算上限)、payment.agent_recurrence(允許重複使用的頻率與次數)、payment.allowed_payment_instruments(可用的付款工具)等等(AP2 Payment Mandate 規格)。
成交那一刻,Agent 把 Open Mandate 轉成 Closed Mandate:實際買了購物車裡的哪些項目、實際付多少錢。關鍵是誰簽這張:
- Human Present(人類在場):由使用者的裝置金鑰
user_sk簽署 - Human Not Present(人類不在場):由 Agent 自己的金鑰
agent_sk簽署
Closed Payment Mandate 上帶有 risk_data 欄位,記錄可信介面在簽署當下蒐集到的風控訊號,人在不在場就是其中之一。這個訊號會一路帶到收單端,讓風控引擎知道該用哪一套模型評估這筆交易。
| Checkout Mandate | Payment Mandate | |
|---|---|---|
| 回答的問題 | 買的東西有被授權嗎? | 這筆錢有被授權嗎? |
| 誰簽署 | open:User closed:User(HP)或 Agent(HNP) | 同左 |
| 誰驗證 | Merchant | Credential Provider、Network、MPP |
| 鎖定什麼 | open:能跟誰買、買什麼、金額上限 closed:最終購物車 | open:能怎麼付、預算多少 closed:實際金額 + 標記人在不在 |
三條綁定線:授權鏈怎麼扣死
圖中間那兩條線,才是整個設計的重點。
第一條:Closed 綁回 Open。 Closed Mandate 以 SD-JWT 的 sd_hash claim 綁定它所依據的那張 Open Mandate。超出授權範圍的 Closed Mandate 不會被接受,驗證方會直接拿 Open Mandate 裡的 constraint 逐條評估。
第二條:Open Mandate 綁定 Agent 的公鑰。 使用者簽 Open Mandate 時,規格要求在 cnf claim 裡放入 agent_pk。白話講就是「我授權這一個 Agent,在這些條件內替我完成交易」。換一個 Agent 拿這張 Open Mandate 去簽 Closed Mandate,簽章驗不過。這叫 Sender-Constrained(發送方受限)憑證,是 v0.1 完全沒有的設計。
第三條:Checkout 與 Payment 互鎖。 Closed Payment Mandate 的 transaction_id 就是 checkout_jwt 的雜湊值;Open Payment Mandate 則用 payment.reference constraint 的 conditional_transaction_id 指回 Open Checkout Mandate 的摘要。付款與購物車用密碼學串起來,偷換任何一邊這個連結都換斷掉。
右邊是商家這一側。checkout_jwt 由 Merchant 簽名,鎖定同一台購物車、同一筆交易,同時也等於承諾了出貨與交付條件(規格範例裡包含 shipping_policy 與 return_policy)。商家事後改不了價格,因為 Closed Checkout Mandate 裡的 checkout_hash 必須與最新的 checkout_jwt 雜湊相符。
整條鏈攤開來:使用者授權、Agent 執行、商家承諾,三方各自簽名、互相鎖定。出爭議的時候,把簽章鏈攤開就知道責任落在誰身上。
Human Present:一次確認,兩份證據

圖上有四個角色:User、Shopping Agent、Merchant(這裡把商家的 MPP 併進來了,實務上就是 Stripe、Adyen 這類 PSP),還有 Credential Provider,可以想成管理你付款方式的錢包服務。
流程走一遍(AP2 Flows 規格):
第一到三步,你跟 Agent 說要買東西,Agent 去商家那邊組購物車、進入結帳。注意第三步,商家回傳的 Checkout 是商家簽過名的。這個簽名是一個承諾:這個 SKU、這個價格,我保證履約。這是第一層保障。
第四步,Agent 去 Credential Provider 取回你可用的付款方式。
第五步是整個流程的核心。 Agent 把最終購物車與付款方式呈現在 Trusted Surface(可信介面)上,你看過、用生物辨識確認,此時你的裝置用 user_sk 同時簽署兩份 Closed Mandate。
這裡有個設計上很漂亮的地方:對使用者來說就是按一次確認,體驗跟平常網購沒兩樣;但密碼學上,產生了兩份各有用途的證據。Checkout Mandate 給商家,日後有爭議可以證明「使用者確實核准了這台購物車」;Payment Mandate 給支付端,讓風控引擎知道這筆交易有 Agent 參與、而且人在現場。
商家先簽保證履約,你再簽確認內容。這就是 AP2 說的 What You See Is What You Pay For:商家改不了購物車,你也賴不掉帳。
第六、七步,Payment Mandate 先交給 Credential Provider 驗證、換成一個 payment token,然後 Agent 帶著 token 與 Checkout Mandate 去找商家。留意一下:Agent 從頭到尾沒有碰過你的卡號,它拿到的只是一個綁定這筆結帳的 token。這是角色隔離,敏感資料只留在該碰它的人手上。
第八、九步,商家驗證 Mandate 與當前購物車狀態一致,MPP 用 token 完成扣款,最後回傳兩份收據:商家簽的 Checkout Receipt,MPP 簽的 Payment Receipt。
收據在 v0.2 是正式物件,不是可有可無的通知。每份收據都有 reference 欄位指回它所綁定的 Closed Mandate 雜湊,而規格明確要求:Shopping Agent 在收到「拒絕先前 Mandate」的收據之前,不得為同一張 Open Mandate 簽署多份重疊的 Closed Mandate。收據是防止重複扣款的狀態機制。更關鍵的是規格加了一句:這些收據必須受完整性保護,不能被 Shopping Agent 的 LLM 竄改。
人在現場的版本,授權邏輯其實跟傳統網購差不多,只是每一步都留下了密碼學證據。真正有趣的是接下來要講的:人不在的時候。
Human Not Present:半夜三點的搶票
場景換一下。
「演唱會門票一開賣就幫我搶,兩張,每張不超過五千,只准跟官方通路買。」
你交代完就去睡覺了。半夜三點票開賣,Agent 要替你完成整筆交易,沒有人可以按確認鍵。
這不是我自己編的場景。Google 在發布公告裡舉的例子就是「在限量票券開賣的那一刻完成拉票與付款」,Human Not Present 就是 v0.2 這一版的主軸。

流程的差別全部集中在簽名的時間點和簽名的人。
第二步,還沒有任何購物車存在。Agent 先把你的條件組成 Open Mandate Content(商家白名單、品項、金額上限),呈現在可信介面上。你用生物辨識確認,裝置用 user_sk 簽署 Open Checkout Mandate 與 Open Payment Mandate。然後你就下線了。
這份 Open Mandate 就是委託書。而且它不是一張空白支票:你的簽章裡面,透過 cnf claim 直接綁定了這個 Agent 的公鑰。換一個 Agent 來,簽章直接失效。
第三到五步,半夜票開賣了。Agent 組購物車、拿到商家簽名的 Checkout,比對條件:官方通路?是。兩張?是。單價五千以內?是。條件全部滿足,這時候 Agent 用它自己的 agent_sk 簽署 Closed Mandate,並透過 sd_hash 綁回你當初簽的那份 Open Mandate。
第六到九步,跟 Human Present 完全一樣:換 token、送商家、驗證、扣款、回收據。唯一的差別是商家多驗一件事:Closed Mandate 背後那份 Open Mandate 的條件,是不是真的都滿足了。
那如果只剩下票價六千的票,條件沒滿足呢?規格設計了一條優雅的退路:商家或 Credential Provider 回傳 unresolved_constraint 錯誤,把使用者拉回迴圈裡,請他直接核准這份 Closed Mandate。Human Not Present 流程可以就地降級成 Human Present 流程,不需要整筆交易重來。這是 v0.2 最務實的一個設計:為條件「對不上的時候」準備了明確的狀態轉移路徑。
資訊隔離:沒有人看到全貌
第三件 v0.2 做對的事,是把隱私從「注意事項」變成了「結構」。
VDC(Verifiable Digital Credentials,可驗證數位憑證)在 v0.2 以 SD-JWT(Selective Disclosure JWT,選擇性揭露 JWT) 實作。SD-JWT 的核心能力是:簽發者把每個欄位雜湊化,持有者可以只揭露其中一部分給特定驗證方,而驗證方仍然能確認整份憑證的簽章有效。
結果就是一張每個角色只拿到殘片的資訊地圖:
| 角色 | 看得到 | 看不到 |
|---|---|---|
| Shopping Agent | 使用者意圖、授權條件、完整購物車 | 真實卡號(只拿到一次性 token) |
| Merchant(含 MPP) | 完整購物車、Closed Mandate 與必要揭露欄位 | 真實卡號、使用者的預算上限與其他授權 |
| Credential Provider | 真實卡號、付款金額與收款方 | 購物車內容(只看到 checkout 的雜湊) |
商家不知道你的總預算有多少,所以沒辦法針對你的授權上限做價格歧視。Credential Provider 知道你付了多少錢給誰,但不知道你買了什麼。Agent 看得到購物車,但永遠碰不到卡號。
規格甚至考慮到了雜湊值本身的洩漏風險:Open Mandate 的 constraint 可能包含與本次結帳無關的意圖資訊,必須用選擇性揭露遮蔽。但只遮住內容還不夠,因為沒揭露的欄位仍然會以雜湊值的形式留在憑證裡,數一數就知道你藏了幾條條件沒給看。所以規格允許可信介面額外塞進一些假的雜湊值(decoy digests,誘餌摘要),讓對方連「到底藏了幾條」都數不準(RFC 9901 §4.2.5)。
至於 checkout_hash,它雜湊的對象是整份含簽章的 checkout_jwt,而簽章本身就是一段猜不到的亂數。攻擊者就算猜中購物車內容,也算不出相同的雜湊值。
任何單一方被攻破,拿到的都只是殘缺的一角。
AP2 假設 Agent 本身就是攻擊者
如果只能從 v0.2 的規格裡挑一句話帶走,我會挑安全考量章節的開頭:
Given the current state of agent security, AP2 assumes that preventing prompt injection attacks is infeasible. Therefore, all LLMs and Agents MUST be considered potential attackers and are explicitly included in the threat model.
AP2 直接放棄了「防住 Prompt Injection」這條路,把 LLM 與 Agent 明確寫進威脅模型裡當攻擊者。
這個假設改變了整個防禦策略的形狀。v0.1 試圖用 Prompt Playback 讓使用者看懂 Agent 的理解;v0.2 則不管 Agent 理解成什麼樣子,它只確保理解錯誤造成的損失有上界。規格在 Manipulated Discovery 威脅的緩解措施裡寫得很清楚:即使 LLM 沒有做出最佳選擇,Closed Mandate 驗證時的 constraint 評估會把最壞情況的財務與邏輯影響嚴格限縮在授權範圍內。
v0.1 的思路很直觀,但它把驗證的最後一哩交給了人的注意力,而注意力是這個世界上最不可靠的基礎設施之一。半夜三點你根本不在,就算在,第十七次彈出確認框時你也已經不看內容了。
這是一個很成熟的工程設計。Agent 被 Prompt Injection 騙去買了一雙不是最划算的鞋,那是產品體驗問題;Agent 被騙去買一台車,那可就嚴重了。AP2 不保證 Agent 每次都買得聰明,但它保證 Agent 買不了你沒授權的東西。
這其實是我們在別的領域早就學會的東西。我們不會要求資料庫「理解」一筆寫入合不合理,我們給它 CHECK、FOREIGN KEY、UNIQUE 這些約束條件,不符合就直接拒絕寫入;我們也不會要求部署腳本「判斷」這次變更安不安全,我們給它 policy gate。工程的成熟,往往就是從「相信執行者會做對」轉向「限制執行者能做錯的範圍」。AP2 v0.2 不過是把同一套思路用在「誰能替你花多少錢、跟誰買什麼」上。
做過資安的人讀到這裡應該會很有既視感:這根本就是 Zero Trust(零信任) 搬到支付授權上。Never trust、always verify、assume breach,AP2 v0.2 幾乎能逐條對應:不預設 Agent 可信(Open Mandate 用 cnf 綁死公鑰)、每一跳都重新驗證(商家驗 Checkout、Credential Provider 與 MPP 驗 Payment)、一開始就假設遲早會出事,所以用 constraint 限制 Agent 只能動到必要的權限,再用資訊隔離把真出事時的災情範圍壓到最小。
但有一個關鍵差別。Zero Trust 假設的攻擊者是冒牌貨:憑證被偷、有人混進內網、假裝成你。防禦的方向就是把身分驗得更嚴格。
AP2 面對的攻擊者不是冒牌貨。你的 Agent 就是你的 Agent,金鑰沒外流,所有身分驗證全部通過。問題出在它讀了商品頁面上一段藏起來的文字,然後就被說服去做別的事。
換句話說,Zero Trust 問的是「你是誰」,但這裡真正需要問的是「你為什麼要這樣做」。身分驗得再嚴也擋不住後者,因為 Agent 每一次簽章都是合法的。這就是為什麼 AP2 除了驗身分,還得替 Agent 畫一條它自己也跨不出去的授權邊界。
→ 回顧系列前四篇: → 【Agentic Payment 系列 #1】HTTP 402 沉睡三十年後醒來:x402 如何讓支付成為網際網路的一等公民 → 【Agentic Payment 系列 #2】信任的代價:AP2 授權機制、A2A 支付整合與三大協議戰場劃分 → 【Agentic Payment 系列 #3】兆美元賽道:Agent 經濟的市場、合規與 Web 4.0 支付堆疊 → 【Agentic Payment 系列 #4】從理論到實作:用 Golang 親手跑一遍 x402 支付流程
如果這篇文章對你有幫助,歡迎分享給對 Agent 經濟與支付協議設計感興趣的朋友。