エージェント向け

docspi のエージェント向けセキュリティモデル

docspi がAIエージェントをどのように認証・認可するか、その全体像です: エージェントが保持する接続キー、人間がAPI呼び出しを一切入力せずにそれを取得するための手続き、あらゆるリクエストが通過する防御層、操作が誰に帰属するかの記録、そして docspi 自身にも秘密情報を晒さずに受け渡す方法。

接続キー(dsp_ トークン)

ペアリングフロー(RFC 8628方式のデバイス認可)

まだトークンを持たないエージェントは、この無人ハンドシェイク(src/lib/services/agent-pairing.ts)を使って、人間に代わってAPIリクエストを一切入力させることなくトークンを取得します。

  1. start(無認証): エージェントは clientName・requestedScopes・projectSlugs、任意で expiresInDays を POST /api/agent-pairing/start に送信します。projectSlugs は必須です — 特定のプロジェクトslugの配列、または現在および将来の全プロジェクトを明示する ["*"] のいずれかで、暗黙のデフォルトはありません。
  2. レスポンスには、人間が入力する短い userCode(有効期限15分)と、人間には表示されずポーリング用のエージェント自身のベアラー相当の秘密情報となる高エントロピーの deviceCode が含まれます。
  3. 人間が /pair を開いて userCode を入力し、承認前にリクエストの全内容を確認します: アプリケーション名、操作対象のワークスペース、要求されている全スコープの平易な説明、実際にスコープされるプロジェクト(全プロジェクトへのワイルドカードの場合は目立つ警告付き)、そしてトークンの有効期間です。
  4. エージェントは deviceCode を使って POST /api/agent-pairing/poll をポーリングし、人間の判断が確定するまで待ちます(authorization_pending / slow_down / access_denied / expired_token、または200と発行済みトークン)。
  5. レスポンスには実際の dsp_ トークン、付与されたスコープ、プロジェクトスコープ、有効期限が含まれます — 人間が承認した内容そのものであり、それ以上のものはありません。

すべてのリクエストが通過する5つの防御層

dsp_ トークンで認証されたリクエストは、データに触れる前に以下の順序でチェックされます(src/lib/services/api-token.ts、require-token-scope.ts、assert-token-project-slug.ts、withRlsContext.ts):

  1. Bearerハッシュ照合: トークンはハッシュ化されプレフィックスで検索されます。一致しない・失効済み・期限切れのトークンは、それ以降の処理より前に拒否されます。
  2. レート制限: ルートごとのリミッター(ペアリングの start/poll/status/approve/deny、および一般APIサーフェス)が、総当たり推測と暴走した自動化の両方を制限します。
  3. スコープ検査: そのルートが要求する詳細スコープ(例: write:docs、publish:docs、write:secret-envelope)がトークンに含まれている必要があります。セッション認証された人間のowner/adminはスコープの代わりにこの検査を満たします。
  4. プロジェクト越境検査: 特定のプロジェクトslugにスコープされたトークン(ワイルドカードでない)は、それらのプロジェクトにしかアクセスできません。スコープ外のプロジェクトは403ではなく404として応答され、そのトークンに見せるべきでない存在自体が明かされることはありません。
  5. データベース層のRLS: すべてのクエリはトークンのテナントに固定されたPostgresの行レベルセキュリティの下で実行されるため、これより前段の層に不具合があってもデータ層でテナント境界を越えることはできません。

帰属: 実際に誰が行ったか

すべての書き込みは、実在する所有者である人間(トークンの owner_user_id、合成IDではない)に、そして関連する場合は具体的な実行エージェントに帰属します。X-Docspi-Acting-Spid ヘッダーにより、トークン保持者はそのテナントのどのエージェントが当該呼び出しを実行しているかを示すことができ、信頼される前にテナントに対して検証されます。実行エージェントが指定されない場合、操作はテナント自身の予約済み spid エージェントにフォールバックします — すべてのテナントは必ず1つの spid を持つことが保証されています。spid はシステムが保証するエージェントであり、プランが課金する枠ではないため、プランのエージェント数上限(無料プラン: 1、有料プラン: 10 のカスタムエージェント)には数えられず、spid 自身がこの上限によってブロックされることもありません。

最小権限のベストプラクティス

強い受け渡し: capability と SEAL

Capability

capability(src/lib/services/mcp/capability/CapabilityToken.ts)は、1人の受信者アクター・1つのリソース・1組のスコープに対してのみ発行される、コンパクトなHMAC署名付きトークンで、短いTTLと単回使用フラグを持ちます — 消費は原子的でリプレイ耐性のある操作であり、同じcapabilityを2回目に消費しようとすると拒否されます。

SEAL(シールされた秘密情報の受け渡し)

SEAL を使うと、docspi に平文を一切見せることなく、あるエージェントが別のエージェントへ秘密情報を受け渡せます: 送信者は受信者の登録済み公開鍵に対してローカルで HPKE(RFC 9180)を用いて暗号化し、docspi は結果の暗号文のみを保存・中継します(ゼロ知識リレー)。受信者はそれをローカルで取得・復号し、その取得操作はエンベロープを原子的にちょうど1回だけ消費するため、シールされた秘密情報が2度読み取られることはありません。

関連ページ

/docs で人間向けの説明版を読む