# Transaction Tokens とは何か——認可の文脈は三ホップのどこで消えるか

> Transaction Tokens（draft -11）を精読し、LayerX の Capability Assertion と並べる。エージェント→ゲートウェイ→プロバイダの三ホップで、認可の文脈がどこで抜け落ちるかを表で示します。

- Published: 2026年8月25日
- Author: Leo Kaka, Engineering
- Tags: security, gateway, agents, api-keys
- Canonical: https://pirouter.ai/ja/blog/authorization-context-across-hops

---
**認可の文脈は、Trust Domain の境界で必ず消えます。その手前で消すかどうかは、設計次第です。**
Trust Domain とは「共通のセキュリティ統制とポリシーを共有するシステムのまとまり」（ドラフト §3）で、
自社のマイクロサービス群は通常これ一つに収まります。Transaction Tokens（Txn-Token）は IETF の OAuth
ワーキンググループが標準化中の短命の署名付き JWT で、一つの Trust Domain の内側で「誰のための、どの取引の、
何の目的の処理か」をリクエストと一緒に各ホップへ運びます。
[LayerX の tkmt 氏が Zenn に書いた記事](https://zenn.dev/layerx/articles/e01465a15e79c2)（はてブで注目）は、
それが解く問題を一文で定式化しています——「入口で行ったユーザー検証の事実と認可の文脈が、ホップの途中で
消えてしまう」。

エージェント基盤も同じ形で、ホップは三つ。エージェントの実行基盤（harness）→ LLM ゲートウェイ → モデル提供者。
前作[「エージェントに渡す鍵の形」](/ja/blog/agent-credentials)が扱ったのは**鍵の形**（短期・スコープ・上限）。本篇が
扱うのは、鍵とは別に**リクエストと一緒に旅をしなければならない文脈**——誰のためか（`sub`）、どの取引か（`txn`）、
何の目的か（`scope`）、どの予算から引くか（`tctx`）。API キーは**鍵の持ち主**を証明しますが**取引**は証明しません。
以下、ドラフト（`draft-ietf-oauth-transaction-tokens-11`、2026-07-30、work in progress）と LayerX の記事の精読です。

## 「私は判定を済ませた」という自己申告しか残らない——LayerX が定式化した問題

題材は、承認フローを持つ「バクラク申請」と、申請に紐づく機微情報を保管する別プロダクト（記事では「サービス X」）の
二段です。承認画面を開くと、(1) バクラク申請が承認ルートや代理設定から「この承認者は閲覧してよい」と判定し、(2) サービス X
の RPC で機微情報の実体を取る。判定材料は (1) にしか無く、承認者はサービス X の権限を持っていないかもしれない。記事は
四つの選択肢を全部却下しており、その理由がそのまま多段ホップ認可の教科書です。

| サービス X の守り方 | 何が壊れるか（記事の理由） |
|---|---|
| permission を要求しない | 承認と無関係なユーザーでも、リソース ID を指定して直接取得できてしまう |
| permission を要求する | 承認者はサービス X の権限を持っていないので、正規の承認画面まで弾かれる |
| サービス X で判定をやり直す | 判定材料はバクラク申請にしか無く、同じ判定を繰り返す。dataloader 経由で何重にも呼ばれるため性能もつらい |
| バクラク申請からの呼び出しを無条件に信頼する | 「バクラク申請を経由した」ことをサービス X が確かめる手段がなければ、ただの自己申告になる |

四行目が核心です。途中のサービスから見ると「呼び出し元の『私は正しい判定を済ませたので信頼してほしい』という
自己申告を信じるしかありません」（記事）。届くのは呼び出し元のサービスアイデンティティだけで、「誰が呼んだか」であって
「何のためか」ではない。

エージェント基盤に読み替えると、バクラク申請の位置に harness、サービス X の位置にモデル提供者、間にゲートウェイ。
harness は「このユーザーの、このタスクのために、このモデルを呼んでよい」と判定済みなのに、API キー一本で上流を呼ぶ構成
（OpenAI 互換 API の一般形）では、ゲートウェイに届くのも上流に送るのも API キー一本。自己申告が二段連なっています。

## Transaction Tokens とは何か——IETF ドラフト -11 を精読する

![IETF Datatracker のページ：Transaction Tokens / draft-ietf-oauth-transaction-tokens-11、Versions 00 から 11 までのタブと改訂の帯グラフ、Type は Active Internet-Draft（oauth WG）、Last updated 2026-08-21（Latest revision 2026-07-30）、Intended RFC status は (None)、WG state は WG Consensus: Waiting for Write-Up、Associated WG milestone は Dec 2026 に IESG へ提出](/blog/images/authorization-context-across-hops-ietf-draft-11.png "図 1 — -11 は 11 番目の改訂で、WG の合意は取れ Write-Up 待ち、IESG 提出の目標は 2026 年 12 月。Datatracker 側の Intended RFC status は未設定（ドラフト本文の見出しは Standards Track）。ページ取得日 2026-08-26。出典：[IETF Datatracker — draft-ietf-oauth-transaction-tokens](https://datatracker.ietf.org/doc/draft-ietf-oauth-transaction-tokens/)。")

[ドラフト](https://datatracker.ietf.org/doc/draft-ietf-oauth-transaction-tokens/)は本稿執筆時点（2026-08-25）で
2026-07-30 付の `draft-ietf-oauth-transaction-tokens-11` が最新、Intended status は Standards Track、有効期限
2027-01-31。ドラフト自身が「work in progress 以外の形で引用するのは不適切」と書いているので、以下は**作業中の
文書を読んだ記録**です。Introduction は、内部ワークロードが侵害されたときに可能になる不正を四つ列挙しています。原文のまま。

> - Invocation of workloads in the absence of a valid transaction.
> - Arbitrary user or workload impersonation.
> - Parameter modification or augmentation.
> - Theft of tokens used to convey authorization context (e.g. OAuth 2.0 access tokens).

一つ目が LayerX の「ID を指定すれば取れてしまう」、三つ目が「途中で書き換えられていないこと」に対応し、二つ目と四つ目は
偽装とトークン窃取そのものです。
Txn-Token の定義は §4 の一文で足ります——「short-lived, signed JWTs that assert the identity of a user or a workload
and an authorization context」。認可の文脈とは §4.1 によれば認可・会計・監査に使う情報で、その要は「取引の意図または目的」
を**できる限り狭く**定義すること。会計（accounting）という語は、後で予算の話に戻ってきます。

### 発行と伝搬——外部エンドポイントが交換し、内側は同じトークンを持ち回る

発行者は Transaction Token Service（TTS）という専用サービスで、Trust Domain ごとに**論理的に一つ**（§3、§10 の MUST）。
ドラフトの Figure 1 を素の形で描き直したのが図 2 で、交換は外部エンドポイント（API ゲートウェイ等）が入口で一度だけ行い、
以降の内部ワークロード間の呼び出しは**同じ** Txn-Token を使います。

![Transaction Tokens の基本フロー：外部クライアントがアクセストークンで外部エンドポイントを呼び、外部エンドポイントが TTS で Txn-Token に交換し、内部ワークロードへは同じ Txn-Token を持ち回る五段の流れ](/blog/images/authorization-context-across-hops-txn-flow.png "図 2 — 交換は入口で一度だけ。内側のワークロードは受け取った Txn-Token を検証し、そのまま次へ渡す。出典：[IETF draft-ietf-oauth-transaction-tokens-11 §8.1 Figure 1](https://www.ietf.org/archive/id/draft-ietf-oauth-transaction-tokens-11.txt) を基に再描画。")

TTS への要求は、HTTP 経由なら [RFC 8693（OAuth 2.0 Token Exchange）](https://www.rfc-editor.org/rfc/rfc8693)の
プロファイルでなければなりません（§5.1、§11 の MUST）。`requested_token_type` に本ドラフトが新設する
`urn:ietf:params:oauth:token-type:txn_token`、`subject_token` に入口で受けたトークンなど。`request_context` と
`request_details` は RECOMMENDED。前作の OBO（On-Behalf-Of）や WIF（Workload Identity Federation）と同じ器です。

伝搬には専用の HTTP ヘッダ `Txn-Token` を使い、`Authorization` は**使ってはならない**（§12。サービス間の認可に使われて
いる可能性があるから、と IANA 節 §16.4）。受け取ったワークロードの検証は三つだけです（§12.2）。JWS 署名、`aud` が自分の
Trust Domain を指すこと、期限内であること。加えて、**下流への呼び出しには受け取ったままの Txn-Token を付ける**（MUST）。

### claims——REQUIRED 七つ、RECOMMENDED 二つ、OPTIONAL 一つ

JWT ヘッダの `typ` は `txntoken+jwt` 固定（MUST）。本体の claims を §9.2 の要否と一緒に並べます。

| claim | 要否 | 意味（§9.2 の要約） |
|---|---|---|
| `iat` | REQUIRED | 発行時刻 |
| `aud` | REQUIRED | このトークンが有効な **Trust Domain**。その外では受け付けてはならない |
| `exp` | REQUIRED | 有効期限 |
| `txn` | REQUIRED | 取引の一意識別子（RFC 8417 §2.2 の定義） |
| `sub` | REQUIRED | 取引の主体。`aud` の Trust Domain 内で一意。OpenID Connect と違い `iss` に紐づかない |
| `scope` | REQUIRED | この取引の目的を「できる限り狭く」。TTS が決め、要求値や外部トークンの scope と一致する必要はない |
| `req_wl` | REQUIRED | Txn-Token を要求したワークロードの識別子 |
| `tctx` | RECOMMENDED | 取引の認可の詳細。Call Chain（一連の内部呼び出し）の間**不変**であるべき値。TTS が決める |
| `rctx` | RECOMMENDED | リクエストの環境文脈（発信元 IP、認証方式、トランスポートなど） |
| `iss` | OPTIONAL | 一つの Trust Domain に束縛され署名鍵も既知のことが多いため必須ではない。鍵が事前に共有されない構成では §13.16 が使用を認める |

なお、検索で `azd` や `purp` という claim 名を見た方へ。Document History によれば `azd` は -04 で `tctx` に、
`purp` は -07 で `scope` に改名されています（各版の全文で確認）。現行 -11 にその名前はありません。

ドラフトの Figure 4（非規範例）は「US の VIP 顧客が MSFT を 100 株買う」取引です。コメントも含めて原文のまま
置きます（`//` コメント付きなので、そのままでは JSON として不正です）。

```json
{
  "iat": 1686536226,
  "aud": "trust-domain.example",
  "exp": 1686536586,
  "txn": "97053963-771d-49cc-a4e3-20aad399c312",
  "sub": "d084sdrt234fsaw34tr23t",
  "req_wl": "apigateway.trust-domain.example", // the internal entity that requested the Txn-Token
  "rctx": {
    "req_ip": "69.151.72.123", // env context of external call
    "authn": "face" // from RFC 8176
  },
  "scope" : "trade.stocks",
  "tctx": {
    "action": "BUY", // parameter of external call
    "ticker": "MSFT", // parameter of external call
    "quantity": "100", // parameter of external call
    "customer_type": { // computed value not present in external call
      "geo": "US",
      "level": "VIP"
    }
  }
}
```

`exp - iat = 360`、つまり 6 分。§6 は寿命を「on the order of minutes or less」と書き、期限切れの subject_token からの
発行を禁じています（MUST NOT）。もう一点、`tctx` の `customer_type` は外部呼び出しに無く、TTS が内部データから計算して
**足した**値です。文脈は「入口で受け取ったもの」だけでなく「入口で確定させたもの」を運ぶ器だと分かります。

## Txn-Token が「してはいけない」こと——§13 の六つの禁止

LayerX の記事は自ら「ざっくりとした概要で、詳細には触れていません」と断っています。設計に直接響く詳細は §13 Security
Considerations の禁止事項で、読み落とすと Txn-Token を「便利な内部 JWT」として使い始めてしまいます。§ 番号は -11 のもので
改版で動くので、監査資料には条番号ではなく要件の文言で引いてください。

| § | 禁止（原文の MUST / MUST NOT） | なぜ |
|---|---|---|
| 13.4 | Txn-Token に、外部エンドポイントが受けたアクセストークンを**含めてはならない** | 抜き出して任意のリソースサーバーで再生できる。Txn-Token の期限は守ってくれない |
| 13.6 | 要求された scope は元の subject_token の scope **以下** | 域内の認可モデルは外部の OAuth scope と別物になりがちで、意図しない拡大が起きる |
| 13.14 | subject_token の scope が判定できないなら**拒否**。不明を「無制限」と扱わない | 拡大していないことを保証できないから |
| 13.12 | Txn-Token でワークロードが自分を**認証してはならない** | 認可の文脈であって身元証明ではない。認証は別建て（ワークロードと TTS 間は §11.5、ワークロード間は仕様外） |
| 13.13 | Txn-Token を OAuth 2.0 アクセストークンとして**使ってはならない** | アクセストークンは「クライアントへの権限の付与」、Txn-Token は「特定の取引の文脈」 |
| 13.15 | 再発行（Txn-Token を subject_token に）では `txn`・`sub`・`aud` を変えず、scope を拡げず、期限切れからは発行しない | 置換は Txn-Token の存在意義を打ち消しかねない |

15.2 も足しておきます。Txn-Token を**そのままログに書いてはならない**（MUST NOT）。残すのはハッシュか、署名を外した
ペイロード。`rctx.req_ip` は多くの法域で個人情報です（15.1）。そして本篇の結論に直結するのが §14 です。Txn-Token は `aud` の Trust Domain の**内側でしか有効ではない**。別の
Trust Domain に文脈を届けたいなら別ドラフト（OAuth Identity and Authorization Chaining Across Domains）を使うべし
（SHOULD）、とだけ書いてあります。域内の道具であり、境界で別の仕組みへ引き継ぐ設計です。

## Capability Assertion と Txn-Token を同じ表に——LayerX の独自実装は何を持ち、何を持たないか

LayerX は同じ問題を、社内で Capability Assertion と呼ぶ仕組みで解いています。記事の定義は「認可判定を行ったサービスが
発行する短命の署名付きトークンで、『どのサービスが、どのテナント・ユーザーについて、何のリソースの閲覧を判定済みか』
を後続のサービスが検証できる仕組み」。実体は protobuf メッセージで、記事が JSON 化しています。

```json
{
  "issuer_service": "workflow.v1.RequestService",
  "tenant_id": "tenant-123",
  "tenant_user_id": "user-456",
  "resources": [
    {
      "field": "request_id",
      "resource_ids": ["req-001", "req-002"]
    }
  ],
  "issued_at": 1755672000,
  "expires_at": 1755672180,
  "token_type": "capability_assertion"
}
```

`expires_at - issued_at = 180` 秒。受け取り側の RPC には proto のカスタムオプションで発行元と TTL を宣言し、共通の
interceptor が発行も検証も行うので、ハンドラには一行も書かない、と記事にあります（以下は受け取り側の抄録、注釈は筆者訳）。

```protobuf
// Receiving side: the RPC that returns sensitive data declares
// which issuers it trusts and which request field to match.
rpc BatchGetRequestDetails(...) returns (...) {
  option (auth.v1.rpc) = {
    capability_assertion_policy: {
      allowed_issuers: ["workflow.v1.RequestService"]
      request_resource_id_field: "request_ids"
      max_ttl_seconds: 180
    }
  };
}
```

二つを項目ごとに並べます。対応の基準は「Txn-Token の当該 claim に相当するものがあるか」です。

| Txn-Token の claim | Capability Assertion | 対応 |
|---|---|---|
| `sub`（取引の主体） | `tenant_id` + `tenant_user_id` | ✓ テナント付きで、むしろ具体的 |
| `req_wl`（要求したワークロード） | `issuer_service` | ✓ 経路の証明として同じ役割 |
| `exp` / `iat` | `expires_at` / `issued_at`（180 秒、`max_ttl_seconds` で受け側が上限） | ✓ ドラフト例の 360 秒より短い |
| `aud`（Trust Domain） | 明示の claim なし。受け側が `allowed_issuers` で発行元を限定 | ⚠ 域の識別子ではなく発行元リストで代替 |
| `txn`（取引 ID） | なし | ✗ 監査・リプレイ検知のための一意 ID は記事の JSON に無い |
| `scope`（取引の目的） | なし。`token_type` は種別のみ | ✗ 「閲覧」に用途が固定されているため不要、と読める |
| `tctx`（不変の認可詳細） | `resources[].resource_ids` | ⚠ 「判定済みのリソース ID」だけ。処理内容やパラメータは運ばない |
| `rctx`（環境文脈） | なし | ✗ |
| 発行者 | 認可基盤（発行者とアクセストークン由来のユーザー情報を書き込み署名） | ✓ TTS と同じ「一箇所で署名」 |
| 伝搬 | レスポンスで返し、次のリクエストに添付 | ⚠ Txn-Token は同一トークンを持ち回る。こちらは発行 RPC の応答経由 |

記事自身の整理は「Txn-Token が伝搬する内容は処理内容そのもの、Capability Assertion は認可判定済みのリソース ID のみ」。
**更新処理**の不変性まで保証したいのがドラフト、参照の判定済みを伝えるだけが要件だったのが LayerX。方向性は揃っていたと
記事は安堵していますが、私の読みでは表の ✗ 二つ（`txn` と `scope`）がエージェント基盤では効いてきます。参照専用なら
要らない二つが、「呼び出しごとに課金が発生する処理」では要る。

## エージェント → ゲートウェイ → プロバイダ：三ホップで何が抜け落ちるか

運びたい文脈は四つ。**誰のためか**（`sub`）、**どの取引か**（`txn`）、**何の目的か**（`scope`）、**どの予算から引くか**
（`tctx` に置く値）。鍵の形は (a) 無制限の長期 API キー（制限付きキーは前作の表の ⚠ に相当）、(b) 短期・スコープ付き
キー（OBO / WIF で交換したもの）、(c) Txn-Token 型の文脈をキーとは別に運ぶ、の三種。(b) は鍵の話、(c) は文脈の話——
前作と本篇の分業です。

表を読む前に、境界の位置を一つ直しておきます。harness は顧客側のソフトウェアで、ゲートウェイ事業者と「共通の
セキュリティ統制」を共有していません。Figure 1 でいえば External client、つまり**ホップ 1 も Trust Domain の境界**です。
Txn-Token が生まれるのは入口——ゲートウェイの外部エンドポイントが API キーを `subject_token` にして自域の TTS と交換した
瞬間——で、harness との間にはまだ存在しません。だから (c) 列のホップ 1 は「入口で何が、何を出所として確定するか」を
読みます。harness とゲートウェイが同じ組織なら、ホップ 1 は域内になりこの区別は消えます。

![三ホップ表：エージェント harness からゲートウェイ、ゲートウェイからモデル提供者への二つの矢印の下に、四つの文脈（誰のため・どの取引・何の目的・どの予算）が各ホップで残るか抜け落ちるかを示す](/blog/images/authorization-context-across-hops-three-hops.png "図 3 — ゲートウェイの入口と出口が Trust Domain の境界。入口で文脈が確定し、出口（§14）で提供者側の鍵の形に畳まれる。")

| 文脈 | (a) 長期 API キー（無制限） | (b) 短期・スコープ付きキー | (c) Txn-Token 型の文脈 |
|---|---|---|---|
| **ホップ 1：harness → ゲートウェイ入口（境界）** | | | |
| 誰のためか（`sub`） | ✗ キーの持ち主（組織かプロジェクト）まで | ⚠ OBO なら `act`（actor）`.sub` に代理者、`sub` に本人。WIF はワークロードの身元 | ⚠ 入口の TTS が確定して署名。出所は三択——ユーザー単位の鍵、harness の申告、(b) の OBO。保証は入口以降の不変性で、申告の真偽ではない |
| どの取引か（`txn`） | ✗ | ✗ 交換トークンに取引 ID は無い | ✓ 入口の TTS が生成。ログの相関キー |
| 何の目的か（`scope`） | ✗ | ⚠ scope は鍵の中にあるが「何をしてよいか」であって「今回何をするか」ではない | ✓ TTS が取引単位に狭く決める。鍵の scope が §13.14 の trusted source |
| どの予算から引くか | ✗ 請求書で気づく | ⚠ 鍵単位の上限は設計可能。取引単位は無い | ✓ 鍵に束縛された予算 ID と上限を TTS が書く（Figure 4 の `customer_type` と同型） |
| **ホップ 2：ゲートウェイ内部（ルータ → 課金 → 上流アダプタ。自社なら内部サービス A → B → C）** | | | |
| 四つとも | ✗ キーの持ち主 ID を引き回すか、ヘッダで自己申告 | ⚠ 検証結果を内部ヘッダに書けば LayerX の「自己申告」。検証済みトークンをそのまま転送すれば署名は残る | ✓ 同一 Txn-Token を持ち回り、各ワークロードが署名・`aud`・`exp` を検証 |
| **ホップ 3：ゲートウェイ → モデル提供者（境界）** | | | |
| 誰のためか | ✗ 上流キーの持ち主＝ゲートウェイ事業者 | ⚠ WIF ならゲートウェイのワークロード身元まで | ✗ 域外で無効（§14）。渡すべきでもない——域内で再生でき（§13.1）、`req_ip` は個人情報（§15.1） |
| どの取引か | ✗ | ✗ | ⚠ 提供者の request ID と `txn` をゲートウェイのログで結べる。提供者には届かない |
| 何の目的か | ✗ | ⚠ 提供者のマッピング権限（前作の表）で「どのモデル・どの操作」まで | ✗ 境界で提供者側の鍵の形に畳まれる |
| どの予算から引くか | ✗ | ⚠ 提供者のプロジェクト単位 | ✗ 境界の手前で数え終えているのが正しい形 |

表から読めることは二つです。第一に、ホップ 2 はいちばん見落とされやすい場所です。入口で検証した結果を `X-Org-Id` の
ような内部ヘッダに書いて引き回すのは、LayerX の四つ目の却下案そのもの。ゲートウェイの Trust Domain に TTS を一つ置き、
入口で交換した Txn-Token を持ち回るのが、ドラフトの絵をそのまま当てた形です。ただし Txn-Token が固めるのは入口で確定した
値であって、`sub` を本当にエンドユーザーにしたいなら、鍵をユーザー単位で発行するか、(b) の OBO トークンを `subject_token`
に使うか。(c) は (b) の代わりではなく、(b) の上に載せるものです。

第二に、ホップ 3 は (c) でも ✗ が並びますが、これは仕様の前提です。モデル提供者はゲートウェイ事業者と別 Trust Domain。
文脈はここで**必ず**提供者側の鍵の形に畳まれ、届くのは前作の表の経路（WIF・auth キー・IAM）が運べる分だけ。設計上の
含意は逆向きになります——**取引単位の判定と課金は、境界の手前、つまりゲートウェイの内側で完了させる**。境界の向こうに
期待しない。

## ゲートウェイが予算を取引単位で数えるなら、どの claim が要るか——設計としての JWT 例

ここは設計メモです。私たち（pirouter のゲートウェイ）も例外ではなく、以下は**設計として**書いているもので、出荷済みの
機能ではありません。担保するのは入口以降の不変性と、課金と監査が同じ取引 ID を見ること。担保しないのは harness の申告の
真偽と提供者ホップ（§14）。Figure 4 を、入口で API キーを `subject_token` にして交換した Txn-Token に置き換えると、
こうなります。フィールド名と値は例示です。

```json
{
  "iat": 1787616000,
  "aud": "gateway.example",
  "exp": 1787616300,
  "txn": "3c9a1f7e-5b2d-4e8a-9f61-0d7c2b4a8e15",
  "sub": "user:acme/7f3a",
  "req_wl": "edge.gateway.example",
  "rctx": {
    "req_ip": "203.0.113.24",
    "key_id": "key_01J6…"
  },
  "scope": "chat.completions",
  "tctx": {
    "model": "provider-x/model-y",
    "max_output_tokens": 4096,
    "budget": {
      "id": "bud_2026-08_acme_agents",
      "cap_usd_micro": 2000000
    },
    "task": "ticket-triage/INC-4821"
  }
}
```

なぜその位置に置くか。

- **`sub` はエンドユーザー**。API キーの持ち主（組織）ではなく、鍵に束縛された利用者、または `subject_token` にした
  OBO トークンの本人を、入口で解決して書きます。
- **`txn` は取引 ID**。無いと、リトライ・フォールバック・ストリーミングの再接続が全部別の呼び出しとして数えられます。
  §13.2 の通り、ログに残せば監査の相関キーです。
- **`scope` は取引の目的**。前作の OBO の `scope` が「何をしてよいか」だったのに対し、こちらは「今回何をするか」。
  §9.2.1 の通り鍵の scope より狭くしてよく、その鍵の scope を TTS が鍵 DB から引けることが §13.14 の前提です。
- **`tctx.budget` は予算の ID と上限**であって、残高ではありません。`tctx` は Call Chain の間**不変**であるべき値の置き場
  （§9.2.3）なので、可変の残高は書けない。課金ワークロードは ID で残高を引き、上限は署名された値と照合する分業です。
  §13.10 も、入口のゲートウェイが取引金額を Txn-Token に持つ例を挙げています。`cap_usd_micro` はマイクロ USD
  （2,000,000 = 2 USD）。
- **`tctx.model` / `max_output_tokens` / `task`** は、Figure 4 の `action` / `ticker` / `quantity` に相当する、入口で
  固定した外部呼び出しのパラメータ。`task` は harness の申告で、真偽は上の三択次第です。
- **`rctx.key_id` は鍵の識別子**で、鍵そのものではありません。§13.4 はアクセストークンを含めることを禁じており、
  API キーも同じ理由で同じ扱い。トークンが漏れても鍵は漏れません。
- **モデル提供者には、このトークンのどれも送りません**（§14、上の第二点）。上流アダプタは提供者側の鍵の形に畳み、
  提供者が返す request ID を `txn` の隣にログしておきます。

`authn` を入れていないのは意図的です。ドラフトの例の `"authn": "face"` は RFC 8176 の認証方式参照値で、API キー認証に
対応する値がそこに無い。無い値を発明するより、省きます。

## 請求書——Txn-Token を持ち込む費用

前作と同じく、費用を先に並べます。

1. **ワークロード認証は別建てで、先に要る**。§13.12 の通り Txn-Token は認証の代わりにならず、内部サービス間の mTLS や
   SPIFFE などの身元基盤が前提。無い組織では、Txn-Token の前に別プロジェクト級の仕事があります。
2. **TTS を一つ建てる**。Trust Domain ごとに論理的に一つ（§10）。署名鍵の配布とローテーション（§13.11）、複数インスタンス
   なら設定改竄への防御（§13.8）。前作の「認可サーバーを一つ足す」と同じ種類の請求書が、もう一枚。
3. **入口に往復が一つ増える**。交換は入口で一度なので内部ホップ数には比例しませんが、TTS が落ちれば入口が止まります。
4. **ログの設計をやり直す**。トークンはそのまま書けず（§15.2）、`req_ip` は個人情報（§15.1）。アクセスログに JWT を
   そのまま吐いている構成は、ここで手が入ります。
5. **リプレイは自力**。§13.1 の通りリプレイ耐性は無く、単一使用チェック（§13.2）には共有状態が要ります。「同じ `txn` を
   二度受けない」を複数インスタンスで保証するのは、それ自体が分散システムの仕事です。

LayerX の Capability Assertion が示唆的なのは、発行と検証を既存の権限基盤と共通 interceptor に相乗りさせ、TTS 相当の
新設コストを抑えた点です。標準を待つか自前で作るかは、この相乗り先が社内にあるかどうかで決まります。

## 月曜にやる三つ

- 入口の認可結果を次のホップに**どう**渡しているかを一行で書く。「内部ヘッダに書いている」なら、LayerX の四つ目の
  却下案と同じ形です。ゲートウェイを買う側なら同じ問いをベンダーへ——検証結果を内部でどう運んでいるか、署名付きか。
- 内部呼び出しの受け側が §12.2 の三点——署名・`aud`・`exp`——のどれかを検証しているか確かめる。どれもしていないなら
  問題は Txn-Token 以前で、内部ヘッダを署名付き JWT にするだけでも LayerX の最小形になります。買う側なら、アクセス
  ログに JWT や API キーをそのまま書いていないかを聞く（§15.2）。
- 取引 ID が**どこで生成され、どこまで届いているか**を追う。タスク単位で費用を出したいなら、その ID が課金ワークロード
  と提供者の request ID の両方と結べるログが要ります。無ければ取引単位の予算はまだ数えられていない——買う側にとっては
  これがベンダーへの最初の質問です。

---

## Sources

### zenn.dev

- [LayerX の tkmt 氏が Zenn に書いた記事](https://zenn.dev/layerx/articles/e01465a15e79c2)

### datatracker.ietf.org

- [IETF Datatracker — draft-ietf-oauth-transaction-tokens](https://datatracker.ietf.org/doc/draft-ietf-oauth-transaction-tokens/)

### ietf.org

- [IETF draft-ietf-oauth-transaction-tokens-11 §8.1 Figure 1](https://www.ietf.org/archive/id/draft-ietf-oauth-transaction-tokens-11.txt)

### rfc-editor.org

- [RFC 8693（OAuth 2.0 Token Exchange）](https://www.rfc-editor.org/rfc/rfc8693)
