mcpField
A
agent-web-identity

agent-web-identity

github.com/dfinityセキュリティ39129 回インストール今日更新
リポジトリ

agent-web-identity について

agent-web-identity は、`icp` CLI を使って Internet Identity をターミナルセッションに連携する手順を案内するスキルです。アプリ固有のプリンシパルで認証済みの canister 呼び出しを行う用途を対象とし、秘密鍵をエージェントに渡さず、状態変更前の確認を重視します。

主な機能

  1. 01`icp identity link web` による連携
  2. 02アプリ固有のプリンシパルを使用
  3. 03ID の秘密鍵を非公開に保持
  4. 04委任とセッションの安全策を説明

活用シーン

  1. 01アプリユーザーとして CLI の canister 呼び出しを認証
  2. 02whoami で連携したプリンシパルを確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/dfinity/icskills --skill agent-web-identity

インストール後、Claude Code で/agent-web-identityを入力して読み込まれたか確認します。

詳細

エージェントのウェブ認証サインイン

概要

Internet Identity(II)は、ブラウザーの外部に保持されているセッションキーに委任を発行する、CLI 認証フローをサポートしています。icp identity link web を使うと、ターミナルセッション(Claude Code などの AI エージェントを含む)から、ユーザーの アプリ固有のプリンシパル としてカナスター呼び出しに署名できます。これは、ユーザーがそのアプリのウェブ UI にサインインしたときに使用するものと同じプリンシパルで、--app <domain> で選択します。

ユーザーは引き続き、自分のブラウザーでパスキーを使って対話的に認証します。エージェントが保持するのは、有効期限付きの委任のみです。ユーザーの II アイデンティティの秘密鍵が公開されることはありません。

前提条件

  • icp CLI がインストールされていること(https://cli.internetcomputer.org)。一般的な使い方については、`icp-cli` スキルを参照してください。
  • ユーザーが Internet Identity(id.ai)を持っており、ブラウザーでのサインインを完了できる状態であること。
  • 初回使用時は、II の設定で自身のアイデンティティに対する CLI access の切り替えをユーザーが有効にする必要があります(落とし穴 1 を参照)。
  • エージェントとユーザーのブラウザーが同じマシン上で動作していること。このフローでは localhost コールバック経由で委任を受け取ります。リモート環境やヘッドレス環境(コンテナー、CI、ウェブセッション)では動作しません。

よくある落とし穴

  1. 初回サインインで「CLI access disabled」画面が表示される。 これは初回実行時に想定される動作であり、エラーではありません。II の設定で自身のアイデンティティに対する CLI access を有効にするようユーザーに伝え、その後、フローを最初からやり直してください。以前のサインイン URL は一度しか使えません(nonce と localhost リスナーが無効になります)。初回使用時は、2 回のサインインが必要になることを見込んでください。

  2. リンクコマンドが何もせず Enter キーの入力を待つ。 バージョン 0.3.x では、まず Press Enter to log in at https://id.ai/cli と表示して stdin の入力を待ちます。その後に初めてフローを開始し、ブラウザーを開こうとします。バックグラウンド実行または非対話型実行では、実際に改行をパイプで渡してください(printf '\n' | icp identity link web ...)。/dev/null からリダイレクトしてはいけません。0.3.2 では、単に EOF を渡してもプロンプトへの応答にならず、コマンドが Press Enter to log in で止まってフローが開始されません。その結果、最初の試行が無駄になり、やり直してユーザーに 2 回対応してもらうことになります。最初の試行で改行を渡せば、フローはすぐに開始されます。

  3. ブラウザーが開いたと思い込まないでください。 サンドボックス化されたシェルや非対話型シェルでは、GUI ブラウザーを起動できないことがよくあります。コマンドの出力を確認してください。完全なサインイン URL が表示されている場合は、ユーザー自身が開けるように伝えてください。ブラウザーの起動も URL の表示も確認できない場合は、その旨を報告してください。推測で URL を組み立てず、ブラウザーウィンドウが表示されたかユーザーに確認してください。

  4. サインインが完了するまでコマンドが停止し、ツールのタイムアウトで強制終了される。 icp identity link web をバックグラウンドタスクとして実行し、ユーザーがサインインを完了したと確認してから結果を確認してください。また、このコマンドが localhost ポートにバインドできる必要があります。サンドボックスでこれがブロックされる場合は、サンドボックス外で再実行する前にユーザーに確認してください。

  5. デフォルトのアイデンティティを使うと、誤ったプリンシパルで署名される。 ユーザーとして実行するすべての icp コマンドには、--identity <NAME> を明示的に指定してください。プロジェクトまたはグローバルのデフォルトアイデンティティ設定に依存せず、決して変更しないでください。

  6. ID の再利用または上書き。 icp identity list に同じアプリにリンク済みの ID が表示されていても、既存の ID は決して再利用しないでください。委任の有効期限が切れている可能性があり、その ID は作成者のものだからです。セッションごとに必ず新しい ID を作成します。icp identity list を確認したうえで、エージェント固有の識別子を先頭に付けた一意の名前 <agent>-<app>-<YYYYMMDD-HHMM> を選びます。たとえば、Claude には claude-oisy-20260611-1530、Cursor には cursor-oisy-... を使用します。識別子がわからない場合は agent- を使用してください。既存の ID は決して 上書きしないでください。icp identity list は空き名を選ぶための読み取り専用の情報源です。このセッションで作成していない ID は、以前の実行時に残されたエージェント固有のプレフィックスが付いているものも含め、決して削除、名前変更、再認証、その他の変更をしないでください。操作対象は $NAME のみです。アプリごとに 1 つの ID を再利用するのではなく、セッションごとに作成する理由は、--app は同じ II ID に対して同じアプリプリンシパルを導出するため、新しい ID を作成しても権限の分離が強化されるわけではないからです。重要なのは作成元の追跡可能性と影響範囲です。セッションごとに ID を作成すれば、icp identity list でどのセッションがどの有効な委任を作成したかを監査でき、クリーンアップ時に該当する ID だけを削除できます。また、別のセッションの reauth によって、このセッションが作業中の委任が予期せず変更される共有 ID を避けられます。

    icp identity list を確認して名前を選ぶ際、過去のセッションで同じアプリに対して作成された古いエージェント固有プレフィックス付きの ID が複数見つかった場合(例:複数の claude-oisy-* エントリ)、先にそれらを整理するかユーザーに確認してください。リストを提示し、ユーザーがそれぞれについて確認するのを待ってから、icp identity delete <NAME> で削除します。明示的な確認なしに削除してはいけません。

  7. --app を指定しなかったためプリンシパルが間違っている。 --app を指定しない場合、プロバイダーはデフォルトの導出元を使用するため、生成されるプリンシパルは対象アプリにおけるユーザーのプリンシパルと一致しません。--app oisy.com のように、アプリのドメインをそのまま(スキーム、ポート、パスを付けずに)指定してください。

  8. 委任の有効期限切れ。 委任には有効期限があり、その期間はサインイン時に ID プロバイダーによって設定されます。icp identity link web には有効期間を制御するフラグはありません。存在しないフラグ(例:--ttl)を指定しないでください。0.3.x では拒否され、コマンド全体が失敗します。署名または有効期限のエラーで呼び出しが失敗し始めたら、icp identity reauth <NAME> を実行します。ユーザーは同じ ID で再度サインインする必要があります。

  9. 引数を明示しないキャニスター呼び出しは自動的にキャンセルされる。 呼び出し引数を省略すると、icp canister call は引数を作成して送信を確定するための対話型プロンプト(Do you want to send this message? [y/N])を表示します。このプロンプトは、非対話型シェルでは直ちにキャンセルされます(User cancelled.)。引数は必ず明示的に渡してください。whoami など引数のないメソッドでも、空のタプル '()' を渡します。

実装

ユーザーを <APP_DOMAIN>(例:oisy.com、nns.ic0.app)にリンクする汎用的なフロー:

# 1. Pick a fresh name (never reuse an existing identity, even one
#    already linked for this app); confirm it doesn't exist
icp identity list
NAME="agent-<app>-$(date +%Y%m%d-%H%M)"
# substitute your own agent prefix for "agent" if known,
# e.g. claude-oisy-20260611-1530, cursor-oisy-...

# 2. Start the link flow IN THE BACKGROUND (keeps the localhost
#    listener alive while the user signs in). Use your harness's
#    background-execution mode if it has one; in a plain shell:
printf '\n' | icp identity link web "$NAME" --app <APP_DOMAIN> \
  > "/tmp/icp-link-$NAME.log" 2>&1 &
# Pipe a real newline to answer the "Press Enter to log in" prompt.
# Do NOT use `< /dev/null`: on 0.3.2 a bare EOF does not satisfy the
# prompt, so the command hangs and you'd have to restart it — which
# prompts the user a second time. The newline starts the flow on the
# first try.

# 3. Read the command's output (the log file above). After the Enter
#    prompt it tries to open the user's browser; if a sign-in URL is
#    printed instead, relay it to the user. Wait for them to confirm
#    sign-in (first run may require enabling CLI access in II settings
#    — restart from step 2 if so)

# 4. Confirm the identity was created
icp identity list

動作確認

リンクした ID として、公開されている whoami キャニスターを呼び出します。

icp canister call --identity "$NAME" --network ic \
  ivcos-eqaaa-aaaab-qablq-cai whoami '()'

(インストールされている CLI バージョンに合わせてフラグを調整してください。icp canister call --help を参照してください。ただし、明示的な --identity と明示的な '()' 引数は必ず指定してください。引数を省略すると、対話型プロンプトが表示され、非対話型シェルでは自動的にキャンセルされます。Pitfall 9 を参照してください。)返されたプリンシパルは、ユーザーが <APP_DOMAIN> にサインインしたときにアプリに表示されるプリンシパルと一致するはずです。ユーザーに確認してもらってください。

エージェント向けセキュリティルール

  • 委任が有効な間、ユーザーのアプリプリンシパルとしての完全な権限が付与されます。特定のカニスターに限定されているわけではありません。このアプリに対する、署名済みの白紙小切手のように扱ってください。
  • whoami による確認を除き、リンク済みの ID で状態を変更するカニスター呼び出しを行う前に、毎回ユーザーに明示的に確認してください。
  • 委任の有効期間は ID プロバイダーが決定するものであり、CLI では変更できません。有効期間を短縮するフラグはありません。
  • ID の鍵素材をエクスポート、表示、またはログに記録しないでください。CLI のデフォルトのキーリングストレージに保管してください。
  • このセッションで一意となる名前を ID に付けてください。セッションキーを保持するキーリングエントリは、サービス icp-cli と ID 名をキーとしており、OS ユーザー全体で共有されます。ICP_HOME を設定しても分離されません。同じ名前で Web ID をリンクする並行実行中のエージェントがいると、互いのセッションキーを上書きします。エージェント名とアプリ名を接頭辞にしてください(例:claude-oisy-<short-id>)。分離に関する詳細は、icp-cli スキルの「並行実行中のエージェントとワークツリー」を参照してください。
  • 出力は最小限にしてください。手順が成功しても、コマンド出力をそのまま表示したり、進捗を説明したりしないでください。ユーザーに必要な情報、つまりサインイン URL、確認の依頼、エラー、最終確認済みのプリンシパルのみを提示してください。
  • 作業が完了しても、独断でリンク済み ID を削除してはいけません。ユーザーは後続の呼び出しに有効な委任を再利用したい場合があります。クリーンアップするかユーザーに確認し、確認が得られた場合に限り icp identity delete <NAME> を実行してください(サブコマンドは delete です。0.3.x では remove は有効なサブコマンドではありません)。ユーザーが削除しないことを選んだ場合は、後で自身で削除できるよう、ID 名とコマンドを伝えてください。
  • セッション開始時に icp identity list を実行し、過去のセッションから残ったエージェント名を接頭辞に持つ古い ID が複数見つかった場合(例:複数の claude-oisy-* エントリ)、新しい ID を作成する前に削除を提案してください。該当する ID の一覧をユーザーに提示して確認を待ち、承認されたものだけを icp identity delete <NAME> で削除してください。一括削除はせず、確認なしに削除してはいけません。

コメント