API キー
API キーの種類と scope、Web ログインでの発行と失効
API キーは /v1 のセッション API を呼ぶ Bearer トークンである。リクエストごとに Authorization: Bearer <key> で送る。キーにできることは scope が決める。エージェント·メンバー·キーの管理といった管理 API はキーでは呼べず(403)、Web ログインの cookie でのみ呼べる。
scope
| scope | できること |
|---|---|
sessions:read | セッション·ターン·イベント·使用量·receipt の読み取り |
sessions:write | セッションの作成、メッセージの送信、push リクエスト |
sessions:control | interrupt, pause, resume, close, terminate, プロファイルの変更 |
sessions:approve | 権限リクエストと質問への回答、push リクエストの承認·拒否、PR の作成とコメント |
sessions:recover | 復旧判断。write や control には含まれない |
scope のないリクエストは、本文を読む前に 403 FORBIDDEN になる。sessions:approve は個人キーにもエージェントキーにも発行時に含められる。ただし、どのキーもそのキーで開始したセッションのリクエストは承認できない(403 self_approval)。別のキーか人が承認する。
種類
| 種類 | 誰が発行 | 動作 |
|---|---|---|
個人キー (personal) | すべてのメンバー、自分の分だけ | 作成した人として動作する。scope は、キーの scope と、その人の現在のロールが許可する scope の共通部分である。その人が無効化されると 401 |
エージェントキー (agent + agent_id) | owner·admin·そのエージェントの管理者 | 人ではなくキー自体として動作する。そのエージェントのリリースで作られたセッションだけを作成し、閲覧する。発行した人が離れても動作し続ける。sessions:approve を含めると、そのエージェントのセッションでリクエストの承認と質問への回答を行う。そのキーで開始したセッションは除く |
エージェントを選ばないキー、つまりワークスペース全体に届くキーはない。agent_id なしで kind: "agent" を送ると 400 BAD_REQUEST になる。
キーには name(前後の空白を除いて 1〜64 文字、任意)を付けて、一覧で見分けられる。付けなければ null である。
expires_at を送らなければ、キーは取り消すまで有効である。Web コンソールの新しいエージェントキー画面は有効期限を 90 日後で埋めておき、空欄にすると期限なしで発行する。
組織が所有し、人に紐づかない組織管理キー(Terraform·CI·SCIM などの自動化用)はまだない。Web コンソールの API キー画面では、owner·admin にだけその場所が「準備中」として見える。発行できるようになったら、有効期限は必須になる。
発行する
Web コンソールで発行するか、Web ログインの cookie で POST /v1/api-keys を呼ぶ。以下は作成の WEB ヘッダーを使う。秘密値(secret)はこのレスポンスで一度だけ返る。変数に入れ、出力しない。
issued=$(curl -sS "$API/v1/api-keys" "${WEB[@]}" \
-d '{"kind": "personal", "name": "laptop", "scopes": ["sessions:read", "sessions:write"]}')
MY_KEY=$(echo "$issued" | jq -r .secret)
KEY_ID=$(echo "$issued" | jq -r .key.id)
echo "$issued" | jq '{kind: .key.kind, name: .key.name, scopes: .key.scopes, receipt: (.receipt_id != null)}'
curl -sS -w '\n' "$API/v1" -H "Authorization: Bearer $MY_KEY"{
"kind": "personal",
"name": "laptop",
"scopes": [
"sessions:read",
"sessions:write"
],
"receipt": true
}
{"status":"ok","owner_id":"…"}発行した人の scope を超える scope をリクエストすると 403 SCOPE_NOT_GRANTABLE になる。
一覧と失効
一覧には、自分の個人キーと、自分が管理するエージェントのキーだけが出る。秘密値は出ない。
last_used_at は、キーが最後に認証に成功した時刻だ。キーごとに 1 分に 1 回までしか記録せず、別のリクエストが同じキーでセッションに書き込んでいる間の使用は記録せずに次の使用で記録する。そのため 1 分より遅れることがある。null は最終使用の記録を始めてから記録された使用がないという意味で、一度も使われていないという意味ではない。created_by_user は発行した人の id と今の表示名だ。その人がワークスペースを離れても、アカウントが無効になっても、名前はそのまま出る。発行者が記録されていないキー(運用者 CLI で作ったキー)では null になる。
curl -sS "$API/v1/api-keys" "${WEB[@]}" | jq -c --arg id "$KEY_ID" '.items[] | select(.id == $id) | {kind, name, scopes, revoked_at, used: (.last_used_at != null), issuer: .created_by_user.display_name}'
curl -sS -X DELETE "$API/v1/api-keys/$KEY_ID" "${WEB[@]}" | jq '{receipt: (.receipt_id != null)}'
curl -sS -o /dev/null -w '%{http_code}\n' "$API/v1" -H "Authorization: Bearer $MY_KEY"{"kind":"personal","name":"laptop","scopes":["sessions:read","sessions:write"],"revoked_at":null,"used":true,"issuer":"…"}
{
"receipt": true
}
401失効したキーは、次のリクエストから 401 になる。すでに失効したキーをもう一度失効させても何も変わらず、receipt_id: null になる。
運用者 CLI
運用者はサーバーでキーを直接発行できる。ローカルスタックでは scripts/local.sh key である(開発用サーバーの実行)。この経路は上記の権限判定を通らない。
scripts/local.sh key <owner> --scopes sessions:read,sessions:write
scripts/local.sh key --workspace <workspace-id> --personal <user-id> --scopes sessions:read,sessions:write<owner> で作ったキーは、その名前を owner として使う。--workspace は --personal と一緒にだけ使う。そのメンバーの個人キーになり、その人として動作する。--personal なしで --workspace だけを渡すか、<owner> の位置にワークスペース id を渡すと拒否する。ワークスペース全体に届くキーはない。エージェントキーは Web コンソールか POST /v1/api-keys で発行する。
SDK でキーを使う
new Werft() は環境変数 WERFT_BASE_URL と WERFT_API_KEY を読む。コードで指定するには baseUrl と apiKey を渡す。どのキーで何を呼んでいるかは auth.me で、サーバーが応答するかは root.get で確認する。scope は要らない。
import { Werft } from "@werft-ai/sdk";
const client = new Werft({
baseUrl: process.env.WERFT_BASE_URL,
apiKey: process.env.WERFT_API_KEY,
});
const me = await client.auth.me();
console.log(me.principal.kind, me.scopes);
const root = await client.root.get();
console.log(root.status);api_key [
'sessions:read',
'sessions:write',
'sessions:approve',
'sessions:control',
'sessions:recover'
]
okSDK はキーを Authorization ヘッダーでのみ送り、ブラウザーと loopback 以外の http:// アドレスではクライアントを作らない。オプションはクライアントのオプションにある。
Web コンソールで発行した個人キー・エージェントキーは、自分が開始したセッションのリクエストを承認できない(403 self_approval)。開発用サーバーの運用者キー(scripts/local.sh key)だけが例外である。セッションを作るキーと承認するキーを分ける方法は承認用のキーを分けて使うにある。エージェントキーには sessions:read、sessions:write、sessions:control、承認者のキーには sessions:read、sessions:approve が必要で、セッションの共有範囲に承認者が含まれている必要がある。