Âmbitos
O que uma chave tem autorização para fazer.
O vocabulário
Um conjunto fechado, resource:action. Pequeno o suficiente para mostrar a uma pessoa numa lista de caixas de seleção, e estável o suficiente para que uma concessão guardada continue a significar o mesmo um ano depois. É o mesmo vocabulário em que uma FUNÇÃO de espaço de trabalho é escrita e que controla as ferramentas MCP, por isso um cliente só de leitura não consegue sequer ver uma ferramenta de envio. Um alfabeto, três superfícies.
| Âmbito | Concede |
|---|---|
| emails:send | Enviar email |
| emails:read | Ler as mensagens enviadas e o seu estado de entrega |
| drafts:read | Ler rascunhos |
| drafts:write | Criar e editar rascunhos |
| threads:read | Ler conversas e mensagens |
| threads:write | Etiquetar, ler e arquivar conversas |
| labels:read | Ler etiquetas |
| labels:write | Criar e editar etiquetas |
| contacts:read | Ler contactos |
| contacts:write | Adicionar, editar e remover contactos |
| audiences:read | Ler audiências e quem está nelas |
| audiences:write | Criar e editar audiências, e alterar quem está nelas |
| calendar:read | Ler eventos e convites de calendário |
| calendar:write | Criar, alterar e responder a eventos de calendário |
| templates:read | Ler modelos de email e pré-visualizá-los |
| templates:write | Criar, editar e enviar com modelos de email |
| domains:read | Ler domínios e o seu estado de DNS |
| domains:write | Verificar e configurar domínios |
| webhooks:read | Ler endpoints de webhook e entregas |
| webhooks:write | Criar, editar e testar webhooks |
| rules:read | Ler regras de correio e testá-las |
| rules:write | Criar, editar e reordenar regras de correio |
| connections:read | Ler que caixas de correio estão ligadas |
| members:read | Ver quem está no espaço de trabalho e o que tem |
| members:write | Adicionar e remover pessoas, e alterar o que podem alcançar |
| roles:read | Ler as funções que este espaço de trabalho define |
| roles:write | Criar, editar e eliminar funções |
| settings:read | Ler as definições da caixa de correio, incluindo a assinatura |
| settings:write | Alterar as definições da caixa de correio e a assinatura |
| keys:write | Substituir o seu próprio segredo sem ninguém abrir a consola |
Uma chave criada sem uma lista de âmbitos pensada fica com emails:send e mais nada. O valor seguro por omissão para uma credencial é a coisa mais estreita que a torna útil.
Uma chave é limitada pela função que está por trás dela
Uma chave pode ser emitida contra uma FUNÇÃO, e uma função é um tecto e não uma segunda concessão. O que a chave pode realmente fazer são os seus próprios âmbitos INTERSETADOS com as permissões dessa função (key.scopes ∩ role.permissions), calculado uma vez na fronteira, em todos os pedidos, antes de se chegar a qualquer endpoint. Nada a jusante sabe que as funções existem: um âmbito que a função não tem simplesmente não está na lista que as verificações de âmbito leem.
Por isso as duas listas leem-se em conjunto e nenhuma ganha sozinha. Uma chave com emails:send sob uma função que não o tem não pode enviar; uma função com emails:send não dá nada a uma chave que nunca o pediu. Marcar um âmbito é pedir autoridade, e a função decide quanto do que pediu recebe.
Uma chave SEM função não tem tecto, e é por isso tão ampla como o espaço de trabalho para o qual foi emitida. É o que todas as chaves criadas antes de as funções existirem trazem e o que um proprietário continua a obter se deixar o campo em branco, por isso uma função nula é o estado MAIS AMPLO em que uma chave pode estar, não o mais estreito. É também por isso que eliminar uma função o obriga a dizer para onde vão as suas chaves: deixá-las órfãs promovê-las-ia todas em silêncio.
A interseção é resolvida por pedido em vez de ficar carimbada na chave no momento da emissão. Isso torna estreitar uma função uma revogação imediata, em vigor na chamada seguinte de quem a usa sem que a chave tenha de ser rodada, e alargar uma é imediato exatamente da mesma maneira, que é a metade que vale a pena recordar.
GET /ping e GET /keys/self comunicam scopes ao lado de grantedScopes e roleId por causa de uma falha em particular. scopes é a lista efetiva e a única que autoriza o que quer que seja; grantedScopes é aquilo com que a chave foi emitida. Tudo o que esteja na segunda e falte na primeira foi retirado pela função, e essa diferença é toda a resposta a "a minha chave tem emails:send e estou a receber insufficient_scope". A correção é uma alteração de função e não mais uma chave.
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"}Cinco permissões nunca podem chegar a uma chave: api-keys:read, api-keys:write, billing:read, billing:write e workspace:manage. São permissões mas não são âmbitos, por isso nenhuma função, por mais generosa que seja, as pode pôr num token: criar outra chave, alterar o que outra chave pode fazer, ou mudar de plano é algo que só uma pessoa com sessão iniciada faz. A única coisa que uma chave pode fazer a si própria é substituir o seu próprio segredo, atrás do âmbito keys:write. GET /roles/permissions marca as cinco com scope: false, que é o que permite a um único componente apresentar tanto a matriz de funções como a lista de caixas de seleção da criação de chaves.
roles:write é, na prática, o vocabulário inteiro, e fingir o contrário seria a documentação mais perigosa. Uma chave que o tenha pode fazer PATCH à própria função que a limita e dar a si mesma tudo o resto, e como o tecto é resolvido por pedido, o mais amplo aplica-se logo na chamada seguinte. Não é um buraco a tapar, já que um editor de funções que não pode editar funções não é um editor de funções. É uma razão para não pôr roles:write numa chave que só precisava de ler a lista de membros.
Âmbito de envio
Independentemente dos âmbitos, uma chave pode ser restringida quanto aos remetentes que pode usar. Traz duas listas. domainAllowlist contém domínios inteiros, e uma chave que tenha um domínio pode enviar como qualquer endereço nele, incluindo endereços criados depois da chave. addressAllowlist contém endereços individuais. Deixe ambas vazias e a chave é tão ampla como o espaço de trabalho, nunca mais. GET /keys/self mostra as duas listas e GET /addresses comunica o que uma dada chave pode efetivamente usar, que é a resposta a um from_address_forbidden inexplicado.
O mesmo conjunto restringe o que a chave lê. O correio enviado, o tracking e o calendário só respondem para endereços que a chave pode usar como remetente, por isso uma chave limitada a um domínio não envia nem lê em nome de outro. Um domínio inteiro permite também à chave definir o host de tracking desse domínio, o que uma chave limitada a endereços individuais não pode fazer.
Três restrições, portanto, e compõem-se em vez de se sobreporem: os âmbitos da chave, as permissões da função acima dela, e os domínios e endereços que pode pôr num cabeçalho From. Um envio precisa das três, e uma recusa nomeia apenas a primeira com que se cruzou.