Přejít na dokumentaci
API

Rozsahy

Co klíč smí dělat.

Slovník

Uzavřená množina ve tvaru resource:action. Dost malá na to, aby se dala člověku ukázat jako seznam zaškrtávátek, a dost stabilní na to, aby uložené oprávnění znamenalo totéž i po roce. Týmž slovníkem je psaná i ROLE pracovního prostoru a tentýž hlídá nástroje MCP, takže klient jen pro čtení odesílací nástroj ani neuvidí. Jedna abeceda, tři plochy.

RozsahUděluje
emails:sendOdesílání e-mailů
emails:readČtení odeslaných zpráv a jejich stavu doručení
drafts:readČtení konceptů
drafts:writeVytváření a úprava konceptů
threads:readČtení vláken a zpráv
threads:writeŠtítkování vláken, označování jako přečtené a archivace
labels:readČtení štítků
labels:writeVytváření a úprava štítků
contacts:readČtení kontaktů
contacts:writePřidávání, úprava a odebírání kontaktů
audiences:readČtení publik a toho, kdo v nich je
audiences:writeVytváření a úprava publik a změny toho, kdo v nich je
calendar:readČtení událostí a pozvánek v kalendáři
calendar:writeVytváření a změny událostí v kalendáři a odpovídání na ně
templates:readČtení e-mailových šablon a jejich náhledy
templates:writeVytváření a úprava e-mailových šablon a odesílání s nimi
domains:readČtení domén a jejich stavu DNS
domains:writeOvěřování a konfigurace domén
webhooks:readČtení webhookových endpointů a doručení
webhooks:writeVytváření, úprava a testování webhooků
rules:readČtení poštovních pravidel a jejich testování
rules:writeVytváření, úprava a přeřazování poštovních pravidel
connections:readČtení toho, které schránky jsou připojené
members:readPřehled o tom, kdo je v pracovním prostoru a co drží
members:writePřidávání a odebírání lidí a změny toho, kam dosáhnou
roles:readČtení rolí, které tento pracovní prostor definuje
roles:writeVytváření, úprava a mazání rolí
settings:readČtení nastavení schránky včetně podpisu
settings:writeZměny nastavení schránky a podpisu
keys:writeVýměna vlastního tajemství, aniž by někdo otevřel konzoli

Klíč vytvořený bez promyšleného seznamu rozsahů dostane emails:send a nic víc. Bezpečná výchozí hodnota pro přihlašovací údaj je to nejužší, co ho ještě dělá užitečným.

Klíč je zastropován rolí, která za ním stojí

Klíč se dá vydat pod ROLÍ a role je strop, ne druhé oprávnění. Co klíč doopravdy smí, je PRŮNIK jeho vlastních rozsahů s oprávněními té role (key.scopes ∩ role.permissions), spočítaný jednou na hranici, při každém požadavku, ještě než se dojde k jakémukoli endpointu. Nic dál po proudu o existenci rolí neví: rozsah, který role nedrží, prostě není v seznamu, který kontroly rozsahů čtou.

Ty dva seznamy se tedy čtou společně a ani jeden sám o sobě nevyhrává. Klíč s emails:send pod rolí, která ho nedrží, odesílat nesmí; role s emails:send nedá nic klíči, který o něj nikdy nepožádal. Zaškrtnout rozsah znamená požádat o pravomoc a role rozhoduje, kolik z toho, oč jste požádali, dostanete.

Klíč BEZ role nemá strop, a je tedy tak široký jako pracovní prostor, pod kterým byl vydán. Tohle nese každý klíč vytvořený dřív, než role existovaly, a tohle vlastník dostane i dnes, když pole nechá být — null role je tedy pro klíč NEJŠIRŠÍ stav, ne nejužší. Proto také smazání role vyžaduje, abyste řekli, kam mají její klíče jít: nechat je osiřet by každý z nich potichu povýšilo.

Průnik se vyhodnocuje při každém požadavku, místo aby se klíči vyrazil při vydání. Zúžení role je díky tomu okamžité odebrání práv, platné už při dalším volání volajícího a bez nutnosti klíč rotovat, a rozšíření je okamžité úplně stejně, což je ta polovina, kterou stojí za to si pamatovat.

GET /ping a GET /keys/self hlásí scopes vedle grantedScopes a roleId kvůli jednomu konkrétnímu selhání. scopes je efektivní seznam a jediný, který k něčemu opravňuje; grantedScopes je to, s čím byl klíč vydán. Cokoli je v druhém a chybí v prvním, vzala role, a ten rozdíl je celá odpověď na „můj klíč má emails:send a dostávám insufficient_scope“. Řešením je změna role, ne další klíč.

Klíč, který role zúžila
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"}

Pět oprávnění se ke klíči nikdy nedostane: api-keys:read, api-keys:write, billing:read, billing:write a workspace:manage. Jsou to oprávnění, ale ne rozsahy, takže žádná role, ať je sebeštědřejší, je na token nedostane: vyrobit další klíč, změnit, co smí jiný klíč, nebo pohnout tarifem dělá jen přihlášený člověk. Jediné, co klíč smí udělat sám sobě, je vyměnit si vlastní tajemství, a to za rozsahem keys:write. GET /roles/permissions označuje těch pět jako scope: false, a právě díky tomu může jedna komponenta vykreslit jak matici rolí, tak seznam zaškrtávátek při vytváření klíče.

roles:write je fakticky celý slovník a tvrdit opak by byla nebezpečnější dokumentace. Klíč, který ho drží, může PATCHnout přesně tu roli, která ho zastropuje, a nadělit si všechno ostatní — a protože se strop vyhodnocuje při každém požadavku, ten širší platí hned při dalším volání. Není to díra, kterou by šlo zalepit, protože editor rolí, který neumí upravovat role, není editor rolí. Je to důvod nedávat roles:write na klíč, který kdy potřeboval jen číst seznam členů.

Rozsah odesílání

Nezávisle na rozsazích se dá klíč zúžit v tom, jako kdo smí odesílat. Nese dva seznamy. domainAllowlist drží celé domény a klíč s doménou smí odesílat jako kterákoli adresa na ní, včetně adres vytvořených až po klíči. addressAllowlist drží jednotlivé adresy. Nechte oba prázdné a klíč je tak široký jako pracovní prostor, nikdy širší. GET /keys/self ukazuje oba seznamy a GET /addresses hlásí, co daný klíč doopravdy smí použít, což je odpověď na nevysvětlené from_address_forbidden.

Táž množina zužuje i to, co klíč čte. Odeslaná pošta, sledování a kalendář odpovídají jen za adresy, jako které klíč smí odesílat, takže klíč omezený na jednu doménu za jinou ani neodesílá, ani nečte. Celá doména navíc klíči dovolí nastavit sledovacího hostitele té domény, což klíč omezený na jednotlivé adresy nesvede.

Tři zúžení tedy, a skládají se, místo aby se přebíjela: rozsahy na klíči, oprávnění role nad ním a domény a adresy, které smí dát do hlavičky From. Odeslání potřebuje všechna tři a odmítnutí jmenuje jen to první, na které narazilo.