ドキュメント本文へスキップ
API

スコープ

キーに許されていること。

語彙

resource:action の形をした閉じた集合です。チェックボックスの一覧として人に見せられるほど小さく、保存された権限が 1 年後も同じ意味を保つほど安定しています。同じ語彙がワークスペースのロールを書くのに使われ、MCP ツールのゲートにも使われるので、読み取り専用のクライアントには送信系のツールがそもそも見えません。1 つのアルファベット、3 つの面です。

スコープ許可される操作
emails:sendメールを送信する
emails:read送信済みメッセージとその配信状況を読む
drafts:read下書きを読む
drafts:write下書きを作成・編集する
threads:readスレッドとメッセージを読む
threads:writeスレッドにラベルを付け、既読にし、アーカイブする
labels:readラベルを読む
labels:writeラベルを作成・編集する
contacts:read連絡先を読む
contacts:write連絡先を追加・編集・削除する
audiences:readオーディエンスと、その構成員を読む
audiences:writeオーディエンスを作成・編集し、構成員を変更する
calendar:readカレンダーの予定と招待を読む
calendar:writeカレンダーの予定を作成・変更し、返答する
templates:readメールテンプレートを読み、プレビューする
templates:writeメールテンプレートを作成・編集し、それを使って送信する
domains:readドメインとその DNS の状態を読む
domains:writeドメインを検証し、設定する
webhooks:readwebhook のエンドポイントと配信を読む
webhooks:writewebhook を作成・編集し、テストする
rules:readメールルールを読み、テストする
rules:writeメールルールを作成・編集し、並べ替える
connections:readどのメールボックスが接続されているかを読む
members:readワークスペースに誰がいて、何を持っているかを見る
members:write人を追加・削除し、到達できる範囲を変更する
roles:readこのワークスペースが定義するロールを読む
roles:writeロールを作成・編集・削除する
settings:read署名を含むメールボックスの設定を読む
settings:writeメールボックスの設定と署名を変更する
keys:write誰もコンソールを開くことなく、自身のシークレットを置き換える

スコープをよく考えずに作成したキーには emails:send だけが付きます。資格情報にとって安全な既定値は、役に立つ最小限のものです。

キーは、その背後のロールに制限される

キーはロールに対して発行でき、ロールは 2 つ目の権限付与ではなく上限です。キーが実際にできることは、自身のスコープとそのロールのパーミッションの積(key.scopes ∩ role.permissions)で、境界でリクエストごとに、どのエンドポイントに到達するよりも前に一度だけ計算されます。その先のコードはロールの存在を知りません。ロールが持たないスコープは、スコープチェックが読む一覧に単に載らないだけです。

したがって 2 つの一覧は合わせて読まれ、どちらか一方だけで決まることはありません。emails:send を持つキーでも、それを持たないロールの下では送信できません。emails:send を持つロールも、それを要求しなかったキーには何も与えません。スコープにチェックを入れることは権限を要求することであり、要求したもののうちどれだけを得られるかはロールが決めます。

ロールを持たないキーには上限がなく、したがって発行元のワークスペースと同じ広さになります。ロールが存在する前に作られたすべてのキーがその状態であり、オーナーがこの欄に触れなければ今もそうなります。つまり null のロールは、キーが取りうる最も「狭い」状態ではなく最も「広い」状態です。ロールを削除するときにキーの移動先を指定させるのも、そのためです。孤立させれば、それらすべてを静かに昇格させてしまいます。

この積は、発行時にキーへ刻み込まれるのではなく、リクエストごとに解決されます。そのためロールを狭めることは、キーをローテーションしなくても呼び出し側の次の呼び出しから効く即時の失効になり、広げるほうもまったく同じように即時です。そちらが覚えておく価値のある半面です。

GET /pingGET /keys/selfscopes の隣に grantedScopesroleId を返すのは、ある 1 つの失敗のためです。scopes は実効的な一覧で、何かを認可するのはこれだけです。grantedScopes はキーが発行されたときの一覧です。後者にあって前者にないものはロールが取り上げたものであり、その差こそが「キーには emails:send があるのに insufficient_scope が返る」への答えのすべてです。対処はキーの作り直しではなくロールの変更です。

ロールに狭められたキー
curl "$OE/ping" -H "$AUTH" {  "ok": true,  "keyId": "4c1b257a66287fd113bd89d0",  "mode": "live",  "scopes": ["emails:read", "threads:read"],  "roleId": "role_c40a95f21cc65d31c2a89e07",  "grantedScopes": ["emails:send", "emails:read", "threads:read"],  "workspaceId": "10417196-e324-4283-af98-66ec62167c47"}

5 つのパーミッションはキーに一切到達できません。api-keys:readapi-keys:writebilling:readbilling:writeworkspace:manage です。これらはパーミッションではありますがスコープではないので、どれほど寛大なロールでもトークンに載せることはできません。別のキーを発行すること、別のキーにできることを変えること、プランを変更することは、サインインした人だけが行うことです。キーが自分自身に対してできる唯一のことは、keys:write スコープの下で自身のシークレットを置き換えることです。GET /roles/permissions はこの 5 つに scope: false を付けます。そのおかげで、ロールのマトリクスとキー作成時のチェックボックス一覧を 1 つのコンポーネントで描画できます。

roles:write は事実上語彙全体に等しく、そうでないふりをするほうが危険なドキュメントになります。これを持つキーは、自分を制限しているまさにそのロールを PATCH して、自分に他のすべてを与えられます。上限はリクエストごとに解決されるので、広げた側は次の呼び出しからすぐ効きます。ロールを編集できないロールエディターはロールエディターではないので、これは塞ぐべき穴ではありません。メンバー一覧を読むだけでよいキーに roles:write を付けない理由だ、ということです。

送信できる範囲

スコープとは別に、キーは送信元にできる範囲でも絞り込めます。キーは 2 つの一覧を持ちます。domainAllowlist はドメイン全体を保持し、あるドメインを持つキーは、キーの作成後に作られたものも含め、そのドメイン上の任意のアドレスとして送信できます。addressAllowlist は個別のアドレスを保持します。どちらも空にしておけば、キーはワークスペースと同じ広さになり、それ以上広くなることはありません。GET /keys/self は両方の一覧を表示し、GET /addresses はそのキーが実際に使えるものを報告します。説明の付かない from_address_forbidden への答えはそこにあります。

同じ集合が、キーの読み取り範囲も狭めます。送信済みメール、トラッキング、カレンダーは、そのキーが送信元にできるアドレスについてのみ応答するので、1 つのドメインに絞られたキーは、別のドメインの代わりに送信することも読むこともできません。ドメイン全体を持つ場合は、そのドメインのトラッキングホストも設定できます。個別のアドレスに限られたキーにはできません。

つまり絞り込みは 3 つあり、互いを上書きせず重ね合わさります。キー自身のスコープ、その上のロールのパーミッション、そして From ヘッダーに入れてよいドメインとアドレスです。送信にはその 3 つすべてが必要で、拒否は最初に引っかかったものだけを示します。