kagi
秘密トークンを承認者のスマホのブラウザー内に持ち、API コールを検閲する。 リクエスト元(スクリプトや AI エージェント)は秘密を知らないまま、承認された API コールの結果だけを受け取る。
流れ
- 承認者はスマホでこのサイトをホーム画面に追加し、マイページ でサインインして通知を登録する。
- 承認 で秘密を保存する。秘密は localStorage に、パスキー(WebAuthn PRF)で暗号化して置かれ、サーバーには送られない。
- 同じ画面で端末を承認者として登録すると、リクエスト用の URL (
/api/sub/:id/req)が発行される。 - リクエスト元が
POST /api/sub/:id/reqに、秘密を[NAME]で埋めたリクエストを送る。サーバーは承認者のスマホに push 通知し、transaction_idを返す。 - 承認者は内容(送信先ホスト・ヘッダー・ボディ)を見て、パスキーで承認する。 ブラウザーが秘密を埋めて API を呼び、結果を手元に保持する。
- リクエスト元の
GET /api/sub/:id/res?transaction_id=…に、サーバーが WebSocket 越しにスマホから結果を取り寄せて返す(一度だけ)。 結果に含まれる秘密の値は[NAME]に置き換えられる。
リクエストの形
POST /api/sub/:id/req
{
"secrets": ["GH_SECRET"],
"url": "https://api.github.com/user",
"method": "GET",
"headers": { "authorization": "Bearer [GH_SECRET]" },
"body": {}
}
→ 202 { "transaction_id": "…", "status": "pending", "notified": true }
GET /api/sub/:id/res?transaction_id=…&wait=25
→ 200 { "status": "delivered", "response": { "status", "headers", "body" } }
→ 202 { "status": "pending" } まだ決まっていない(再度呼ぶ)
→ 403 / 502 / 410 拒否 / 呼び出し失敗 / 期限切れ・受け渡し済みAPI はブラウザーから呼ばれるので、呼び先が CORS でこのオリジンを許可している必要がある。