なぜ単純にエージェントを機密操作から遮断しないのか?
アプリケーション内の操作は、重要度が同じではありません。パスワードの変更、チームメンバーの追加、データのエクスポート、プロジェクトの削除、注文の承認。これらのいずれかが適切な権限なしに実行されれば、被害は現実的です。
同時に、アプリ内で正当に行われる作業の多くは自動化によって処理されています。ユーザーがアシスタントに設定更新を依頼する。パートナー連携が定期的にレコードを作成する。社内エージェントがサポートチケットを起票する。機密ルートへの自動クライアントをすべてブロックすると、そうした作業が壊れ、人は手作業に戻されるか、より安全に管理しにくい回避策へ追い込まれます。
答えは「エージェントをブロックする」でも「エージェントを信頼する」でもありません。操作のリスク、リクエストの背後にある権限、そしてactorに関する証拠が、それぞれ別々の役割を担うモデルです。このガイドでは、そのモデルを組み立てます。より広い背景については、人間とAIエージェント向けのアプリレベルのポリシー設計を参照してください。
Step 1: ルートをリスクで段階分けする
まず、クライアントではなく操作を分類します。多くのアプリケーションでは、次の3段階で十分です。
| 段階 | 例 | デフォルト要件 |
|---|---|---|
| Low | 公開データの閲覧、検索、自分のダッシュボードの表示 | 必要であれば通常の認証 |
| Medium | 自分のコンテンツの作成または編集、閲覧者の招待 | 認証済みで、対象リソースへの認可あり |
| High | 認証情報の変更、所有権の変更、一括エクスポート、削除、承認 | 認可に加えて段階的確認またはレビュー |
段階はルート設定に書き込み、コードレビューで見えるようにします。
type Tier = "low" | "medium" | "high";
export const routeTier: Record<string, Tier> = {
"GET /projects": "low",
"POST /projects": "medium",
"POST /projects/:id/members": "medium",
"POST /account/password": "high",
"POST /exports": "high",
"DELETE /projects/:id": "high",
};段階はゆっくり変わり、理解しやすいものです。このガイドの他のすべては、ここにぶら下がっています。
Step 2: ID、認証情報、認可はどう違うのか?
しばしば、次の3つの問いが混同されます。
- 誰または何が操作しているのか? これはactorの証拠です。対話的な人間、人間のAI支援付き、エージェント、またはUnknownであり、basisとしてVerifiedやDeclaredのようなものがあります。
- どの認証情報が提示されたのか? セッションcookie、API key、OAuth access token。
- この認証情報は、このリソースに対してこの操作を実行してよいのか? これが認可です。
検証済みのエージェント署名(RFC 9421)は、1つ目の問いにはよく答えます。3つ目については何も語りません。この点は署名されたAIエージェント要求が証明するものと、証明しないもので詳しく扱っています。適切なscopeを持つOAuth tokenは、3つ目の問いに答えます。1つ目についてはほとんど語りません。High段階の操作では、3つ目の問いに対する十分な答えが常に必要です。そのうえで、1つ目を使って、どの程度の追加確認を求めるかを決めます。
interface Context {
actor: { actor: "human" | "human_ai" | "agent" | "unknown"; basis: "verified" | "declared" | "inferred" | "unknown" };
credential: { type: "session" | "oauth" | "api_key"; scopes: string[]; subject: string };
}
function authorized(ctx: Context, action: string, resourceOwner: string): boolean {
return ctx.credential.subject === resourceOwner && ctx.credential.scopes.includes(action);
}好ましいactor結果が出たからといって、認可が緩むことはありません。actorの文脈は、要件を追加するか、同じくらい安全な経路の間で選ぶためにのみ使います。
Step 3: 人の代わりに動くエージェントには委任された権限を使う
エージェントがユーザーの代理で動く場合は、ユーザーのセッションを再利用させるのではなく、権限を限定した独自の認証情報を与えます。OAuth 2.0が標準的な手段です。ユーザーは特定のclientに対して特定のscopeを承認し、tokenにはそのclientが記録されます。RFC 9700であるOAuth 2.0 Security Best Current Practiceは、それを安全に展開する方法を示しています。MCP serverも同じパターンに従います。MCP authorization specificationでは、保護されたMCP serverをOAuth 2.1 resource serverとして扱います。私たちの投稿あなたのMCP serverに誰が呼び出しを送っているのか?では、これをtool callに適用しています。
これにより、機密操作に必要なものがそのまま得られます。
- tokenは、どのclientが誰のために動いているのかを示します。
- scopeにより、実行できる範囲が制限されます。
calendar:writeを持つスケジューリングエージェントは、パスワードを変更できません。 - ユーザーは、自分の認証情報を変えずにgrantを取り消せます。OAuth 2.0 Token Revocation (RFC 7009)は、tokenを無効にすべきだとauthorization serverにclientが伝える方法を定義しています。
- audit logには、ユーザーではなくエージェントがその操作を実行したことが記録されます。
アプリがまだ委任された認証情報をサポートしていない場合は、エージェントが最も頻繁に必要とする操作から優先して実装してください。これは、自動アクセスに対する最も効果的な制御です。
Step 4: どのタイミングで段階的確認を求めるべきか?
段階的確認とは、機密操作の瞬間に追加の確認を求めることです。OAuthで保護されたAPIについては、RFC 9470が、現在のtokenの認証が十分に強くない、または十分に新しくないことをresource serverがclientに伝える方法を定義しています。適切な段階的確認は、誰が操作しているかによって変わります。
- 対話的な人間 (Human, Human + AI): 再認証(NIST SP 800-63Bの再認証要件を参照)、WebAuthnに基づくpasskeyのプロンプト、またはワンタイムコード。
- 委任された認証情報を持つエージェント: ユーザーが明示的に付与した、High段階の操作専用のscope、または帯域外でユーザーに送る確認。
- Unknown: ルートの既存の強いチェックを、そのまま維持。
type Requirement = "none" | "reauth" | "explicit_scope" | "user_confirmation" | "review";
function stepUp(tier: Tier, ctx: Context): Requirement {
if (tier !== "high") return "none";
const { actor } = ctx.actor;
if (actor === "human" || actor === "human_ai") return "reauth";
if (actor === "agent" && ctx.credential.type === "oauth") return "explicit_scope";
if (actor === "agent") return "user_confirmation";
return "reauth";
}Humanの結果が段階的確認を省略するわけではないことに注意してください。それは、対話的な人間に適した段階的確認を選ぶだけです。推論は誤ることがあるため、チェックをなくすのではなく、その形を変えるべきです。
Step 5: 判断が必要な場合は人によるレビューに振り分ける
一部の操作は、まれで、影響が大きく、安全に自動化するのが難しいものです。たとえば、顧客データの一括エクスポート、認証情報を失ったあとのアカウント復旧、組織の削除などです。こうしたケースでは、自動ルールよりもレビューキューのほうが適していることがよくあります。
actorの文脈があれば、レビュー担当者に証拠を渡せるため、レビューはより速く、より公正になります。証拠には、クラス、basis、使用された認証情報、類似リクエストの履歴が含まれます。レビュー担当者が判断します。分類は、その判断材料になります。
function shouldReview(route: string, ctx: Context): boolean {
const reviewRoutes = new Set(["POST /exports", "POST /account/recover"]);
if (!reviewRoutes.has(route)) return false;
return !(ctx.credential.type === "oauth" && ctx.credential.scopes.includes("export:bulk"));
}Step 6: 段階ごとに失敗時の動作を決める
actorの評価はタイムアウトすることもあれば、証拠が不足することもあります。事前に、何が起きるかを決めておきます。
- Low段階: fail open。リクエストは通常どおり進みます。
- Medium段階: 既存の認可を維持したうえで fail open。
- High段階: 既存の強いチェックに対して fail closed。actor証拠が欠けていても保護は弱まりませんし、通常のチェックで通るはずだったリクエストをブロックすることもありません。
重要なのは対称性です。actor評価が失敗しても、その操作は、actorの文脈を追加する前とまったく同じ安全性で、まったく同じ利用可能性を保つべきです。
Step 7: 推論だけで人に関する重大な निर्णयをしない
推論による分類は、人物についての事実ではなく、interactionについての証拠です。セッションが自動化されているように見えた、またはAI支援されているように見えたという理由だけで、就職応募、信用判断、試験結果、住居、または必須サービスへのアクセスを拒否してはいけません。こうしたフローでは、actorの文脈を使って人によるレビューや代替の検証経路のようなプロセスを選び、本人がそれを完了できるようにしてください。
これは公正性の原則であると同時に、実務上の原則でもあります。推論には誤検知があり、この種のフローでの誤検知のコストは、何も悪いことをしていない人に降りかかります。
Step 8: まずは観測から段階的に展開する
実際のリクエストに影響を与える前に、observiation と preview mode で実行します。
- 段階、actor class、basis、認証情報の種類、そしてポリシー上必要になる段階的確認を記録する。
- High段階のリクエストをclassごとにサンプル確認する。正当なエージェントは委任された認証情報を使っているか、それともユーザーのセッションを再利用しているか。
- 見つかった問題を修正する。多くの場合、scope付きの認証情報を提供することで解決し、そのうえで enforce する。
- 単一ルートの小さな一部に対して enforce し、完了率を測定してから範囲を広げる。
Step 9: 「誰が、誰の代理で」を答えられる監査証跡を残す
すべてのHigh段階の操作について、後から何が起きたかを再構成できるだけの情報を記録します。
- リクエスト時点のactor class と basis,
- 付与された認証情報の種類、それが付与されたclient、そしてそれが表すsubject(OAuth 2.0 Token Exchange(RFC 8693)は、まさにこの種の「誰のために動いているか」という関係を記録するための
actclaim を定義しています), - 操作を許可したscope,
- 適用された段階的確認またはレビュー要件と、その結果。
audit.write({
action: "project.export",
actor: ctx.actor,
client: ctx.credential.type === "oauth" ? clientIdFromToken(req) : undefined,
subject: ctx.credential.subject,
scopes: ctx.credential.scopes,
requirement,
outcome: "approved",
at: new Date().toISOString(),
});この証跡があれば、「このプロジェクトを削除したのは人だったのか、アシスタントだったのか、そして誰が承認したのか」といった問いに、明確に答えられます。それにより、インシデント対応は速くなり、アプリ内の自動化支援が説明責任を持つという信頼も得られます。
具体例
あるプロジェクト管理アプリで、アシスタントがユーザーのためにタスクの期限を更新し、時々プロジェクト全体のエクスポートを試みています。
- タスクの更新はMedium段階です。アシスタントは
tasks:writeを持つOAuth tokenを使います。認可済みで、段階的確認は不要です。許可されます。 - プロジェクトのエクスポートはHigh段階です。アシスタントのtokenには
export:bulkがありません。アプリはユーザーに確認リクエストを送ります。ユーザーが承認し、アプリはそのclientにscopeを付与します。 - Unknownのclientが、再利用されたsession cookieを使って同じエクスポートを試みます。既存の再認証プロンプトが、そのまま適用されます。
エージェントであることを理由に、誰もブロックされませんでした。影響の大きい操作には、すべて明示的な権限がありました。
Proof of Actor が位置付けられる場所
Proof of Actor は、このモデルの actor 側を提供します。誰または何が、どの basis で動いているのかを示します。アプリケーション側では、認証、認可、そして最終判断を保持します。actor を Detect し、各class が機密ルートをどう使うかを Understand し、各リクエストを適切な assurance レベルへ Route します。
私たちのチームと一緒に、あなたのアプリケーション向けにこれを設計するには、早期アクセスに申し込むを参照してください。SaaS シナリオの詳細については、SaaS Apps & Websitesを参照してください。
Sources
- RFC 6749: The OAuth 2.0 Authorization Framework: client向けのスコープ付き委任認証情報
- RFC 9700: Best Current Practice for OAuth 2.0 Security: OAuth展開に関する現在のセキュリティ指針
- RFC 7009: OAuth 2.0 Token Revocation: ユーザーの認証情報を変えずにgrantを取り消す方法
- RFC 9470: OAuth 2.0 Step Up Authentication Challenge Protocol: より強い、またはより新しい認証が必要であることを通知する方法
- RFC 8693: OAuth 2.0 Token Exchange: 委任のための
act(actor) claim - MCP specification 2026-07-28: Authorization: OAuth 2.1 resource serverとしてのMCP server
- NIST SP 800-63B: Authentication and Authenticator Management: 再認証の指針
- W3C Web Authentication (WebAuthn) Level 3: passkeyプロンプトの標準
- RFC 9421: HTTP Message Signatures: 検証済みのエージェント署名が示すもの