Pular para o conteúdo
Docs

Guia

Permita que os usuários conectem a sua aplicação ao workspace deles no Emailit com OAuth 2.1 e PKCE, incluindo registro do cliente, atualização de tokens, revogação e erros.

Atualizado em 1 de out. de 2026

O Emailit mantém um servidor de autorização OAuth 2.1 em https://api.emailit.com. Use-o quando você criar uma integração, como um CRM, uma ferramenta no-code ou um cliente de IA, que age em nome de usuários do Emailit. Os seus usuários fazem login e aprovam o acesso no navegador, e você recebe tokens para os workspaces que eles escolherem sem nunca lidar com as chaves de API deles. É o mesmo fluxo que o servidor MCP usa.

Como funciona

  1. Registre um cliente com o registro dinâmico de clientes ou hospede um documento de metadados do client ID.

  2. Envie o usuário para a URL de autorização com um code challenge PKCE.

  3. O usuário faz login no Emailit, escolhe os workspaces que a sua aplicação pode usar e aprova o escopo solicitado.

  4. O Emailit redireciona de volta para a sua URI de redirecionamento com um código de autorização de uso único.

  5. Troque o código por um token de acesso de 15 minutos e um token de atualização.

  6. Chame a API com o token de acesso e atualize-o quando ele expirar.

Endpoints

Método Caminho Finalidade
GET /.well-known/oauth-authorization-server Metadados do servidor de autorização (RFC 8414)
GET /.well-known/oauth-protected-resource Metadados do recurso protegido para a API REST
GET /.well-known/oauth-protected-resource/mcp Metadados do recurso protegido para o servidor MCP
POST /oauth/register Registro dinâmico de clientes (RFC 7591)
GET /oauth/authorize Login e consentimento no navegador
POST /oauth/token Trocar um código ou um token de atualização
POST /oauth/revoke Revogar uma autorização com o token de atualização dela (RFC 7009)
GET /oauth/grants Listar autorizações (as do usuário conectado ou as de um workspace, com uma chave de API)
POST /oauth/grants/:id/revoke Revogar uma autorização
PUT /oauth/grants/:id/workspaces Alterar quais workspaces uma autorização pode usar (o usuário que conectou o app)

Todos os caminhos ficam em https://api.emailit.com.

Descobrir o servidor

Terminal
curl https://api.emailit.com/.well-known/oauth-authorization-server
JSON
{
  "issuer": "https://api.emailit.com",
  "authorization_endpoint": "https://api.emailit.com/oauth/authorize",
  "token_endpoint": "https://api.emailit.com/oauth/token",
  "registration_endpoint": "https://api.emailit.com/oauth/register",
  "revocation_endpoint": "https://api.emailit.com/oauth/revoke",
  "jwks_uri": "https://api.emailit.com/.well-known/jwks.json",
  "code_challenge_methods_supported": ["S256"],
  "grant_types_supported": ["authorization_code", "refresh_token"],
  "response_types_supported": ["code"],
  "token_endpoint_auth_methods_supported": ["none", "client_secret_basic", "client_secret_post"],
  "client_id_metadata_document_supported": true,
  "authorization_response_iss_parameter_supported": true,
  "scopes_supported": ["sending", "full"]
}

Os clientes MCP começam pelos metadados do recurso protegido. Uma requisição não autenticada para https://api.emailit.com/mcp retorna 401 com WWW-Authenticate: Bearer resource_metadata="https://api.emailit.com/.well-known/oauth-protected-resource/mcp", e esse documento aponta para o servidor de autorização:

JSON
{
  "resource": "https://api.emailit.com/mcp",
  "authorization_servers": ["https://api.emailit.com"],
  "bearer_methods_supported": ["header"],
  "scopes_supported": ["sending", "full"]
}

Escopos

Escopo Concede
sending Enviar e encaminhar e-mails, além de reagendar, cancelar e tentar de novo os envios. O mesmo acesso de uma chave de API Sending Only.
full Todos os endpoints da API REST e todas as ferramentas MCP. O mesmo acesso de uma chave de API Full Access.

full já inclui tudo o que sending permite. Solicite sending se a sua aplicação só envia e full nos outros casos; sending full, separado por espaço, também é aceito. Se você omitir scope, o Emailit usa todos os escopos que o cliente registrou.

Registrar o seu cliente

Você pode registrar um cliente de duas formas. As duas funcionam com todos os fluxos desta página.

Registro dinâmico de clientes

Envie uma requisição de registro. Não é preciso autenticação, e cada endereço IP pode registrar até 20 clientes por hora.

Terminal
curl https://api.emailit.com/oauth/register \
  -H "Content-Type: application/json" \
  -d '{
    "client_name": "Acme CRM",
    "redirect_uris": ["https://crm.acme.com/oauth/emailit/callback"],
    "grant_types": ["authorization_code", "refresh_token"],
    "response_types": ["code"],
    "scope": "full",
    "token_endpoint_auth_method": "client_secret_basic",
    "client_uri": "https://crm.acme.com",
    "logo_uri": "https://crm.acme.com/logo.png"
  }'
Campo Obrigatório Descrição
client_name Sim Exibido na página de consentimento. Até 200 caracteres.
redirect_uris Sim De 1 a 10 URIs de redirecionamento. Consulte Regras das URIs de redirecionamento.
grant_types Não Deve incluir authorization_code; pode incluir refresh_token. O padrão são os dois.
response_types Não Apenas code.
scope Não Escopos separados por espaço. O padrão é sending full.
token_endpoint_auth_method Não none (padrão) para clientes públicos, como apps de desktop, mobile e de navegador; client_secret_basic ou client_secret_post para aplicações do lado do servidor.
client_uri Não A página inicial da sua aplicação.
logo_uri Não Logo exibido na página de consentimento.

A resposta 201 repete os metadados e adiciona um client_id. Os clientes confidenciais também recebem um client_secret, exibido uma única vez:

JSON
{
  "client_id": "3e8a1f52-7c4b-4d29-8e6f-1a5b9c0d2e73",
  "client_id_issued_at": 1790847000,
  "client_name": "Acme CRM",
  "redirect_uris": ["https://crm.acme.com/oauth/emailit/callback"],
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"],
  "scope": "full",
  "token_endpoint_auth_method": "client_secret_basic",
  "client_uri": "https://crm.acme.com",
  "logo_uri": "https://crm.acme.com/logo.png",
  "client_secret": "Ky7WI2z5HxoT6q1z19tuiIev_U1zX0_FKhIIfh0OBco",
  "client_secret_expires_at": 0
}

client_secret_expires_at é sempre 0: os segredos não expiram. Todo cliente, público ou confidencial, deve usar PKCE.

Documento de metadados do client ID

Se a sua aplicação pode hospedar um arquivo JSON estático, você pode pular o registro. Publique um documento em uma URL HTTPS e use essa URL como o seu client_id:

https://crm.acme.com/oauth/client.json
{
  "client_id": "https://crm.acme.com/oauth/client.json",
  "client_name": "Acme CRM",
  "client_uri": "https://crm.acme.com",
  "logo_uri": "https://crm.acme.com/logo.png",
  "redirect_uris": ["https://crm.acme.com/oauth/emailit/callback"],
  "grant_types": ["authorization_code", "refresh_token"],
  "token_endpoint_auth_method": "none",
  "scope": "full"
}
  • O client_id do documento deve ser exatamente igual à URL do documento.
  • token_endpoint_auth_method deve ser none. São clientes públicos que dependem de PKCE.
  • As URIs de redirecionamento HTTPS devem estar no mesmo host do documento.
  • O Emailit busca o documento durante a autorização, com um timeout de 5 segundos e sem seguir redirecionamentos, e o mantém em cache por 5 minutos.
  • A página de consentimento mostra o host do documento, por exemplo, crm.acme.com, em vez de client_name.

Os clientes de IA usam este método: o ChatGPT, o Claude e o Grok se identificam com os próprios documentos de metadados do client ID, então se conectam sem se registrar antes. Para o Grok, o Emailit também aceita redirecionamentos para console.x.ai.

Regras das URIs de redirecionamento

  • URIs https:// são permitidas.
  • http:// só é permitido para hosts de loopback: 127.0.0.1, localhost e [::1]. Em URIs de loopback, a porta pode ser diferente no momento da autorização, mas o host, o caminho e a query devem corresponder. localhost e 127.0.0.1 são hosts diferentes.
  • Esquemas de uso privado, como cursor://, vscode:// ou com.acme.crm://, são permitidos para apps nativos.
  • URIs file, ftp, data, javascript, blob, about e vbscript, e qualquer URI com um #fragment, são rejeitadas.
  • Fora as portas de loopback, a redirect_uri que você envia deve ser exatamente igual a uma URI registrada.

Enviar o usuário para o Emailit

Crie um verifier e um challenge PKCE, além de um state aleatório, para cada autorização:

JavaScript
import { createHash, randomBytes } from 'node:crypto';

const codeVerifier = randomBytes(32).toString('base64url');
const codeChallenge = createHash('sha256').update(codeVerifier).digest('base64url');
const state = randomBytes(16).toString('base64url');
// Store codeVerifier and state in the user's session.

Depois, redirecione o navegador do usuário para o endpoint de autorização:

Text
https://api.emailit.com/oauth/authorize
  ?response_type=code
  &client_id=3e8a1f52-7c4b-4d29-8e6f-1a5b9c0d2e73
  &redirect_uri=https%3A%2F%2Fcrm.acme.com%2Foauth%2Femailit%2Fcallback
  &scope=full
  &state=Jq3k9V0n2xR7bLm1
  &code_challenge=zsrvXVr2pbLDHbccAx_NY9osQ6nwqTnDZlIeFWKQOsg
  &code_challenge_method=S256
  &resource=https%3A%2F%2Fapi.emailit.com
Parâmetro Obrigatório Descrição
response_type Sim code
client_id Sim O seu client ID ou a URL do seu documento de metadados.
redirect_uri Sim Uma das suas URIs de redirecionamento registradas.
code_challenge Sim SHA-256 do code verifier, codificado em Base64url.
code_challenge_method Recomendado S256. plain não é aceito.
scope Recomendado sending ou full. Deve ser um escopo que o cliente registrou.
state Recomendado Um valor aleatório que você confere no callback.
resource Não O recurso que você quer chamar (RFC 8707): https://api.emailit.com para a API REST ou https://api.emailit.com/mcp para o MCP. Os tokens funcionam nos dois de qualquer forma.

Abra essa URL no navegador do usuário. Não a busque a partir do seu backend.

O que o usuário vê

  1. Login no Emailit. O usuário digita o e-mail e a senha. Se ele usa um app autenticador para a autenticação de dois fatores, digita em seguida o código dele ou um código de recuperação.
  2. Escolha dos workspaces. A página mostra o seu logo, o nome do seu cliente (ou o host do seu documento de metadados) e os escopos que você solicitou. O usuário escolhe All my workspaces, que inclui os workspaces que ele criar ou em que entrar depois, ou Only these workspaces com os que ele marcar, e escolhe por onde a sua aplicação começa.
  3. Permissão de acesso. O usuário seleciona Allow access ou Deny.

Uma autorização pode cobrir vários workspaces. O usuário pode alterar a lista depois em Account > Connected apps no painel, e a sua aplicação vê a mudança na próxima requisição.

Na aprovação, o Emailit redireciona para a sua URI de redirecionamento:

Text
https://crm.acme.com/oauth/emailit/callback?code=XvRKyG5Pkplrd3xkRNaEayKkpkebEMdF&state=Jq3k9V0n2xR7bLm1&iss=https%3A%2F%2Fapi.emailit.com

Confira se state corresponde ao valor que você guardou e se iss é https://api.emailit.com. O código vale por 10 minutos e pode ser usado uma vez. Se o usuário selecionar Deny, o redirecionamento leva error=access_denied.

Trocar o código por tokens

Faça um POST para o endpoint de token como application/x-www-form-urlencoded (JSON também é aceito). Envie a mesma redirect_uri e o code verifier original:

Terminal
curl https://api.emailit.com/oauth/token \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d grant_type=authorization_code \
  -d code="$CODE" \
  -d redirect_uri=https://crm.acme.com/oauth/emailit/callback \
  -d code_verifier="$CODE_VERIFIER"

Com client_secret_basic, envie o client ID e o segredo no cabeçalho Authorization: Basic. Com client_secret_post, envie client_id e client_secret como campos do formulário. Não envie o segredo das duas formas.

JSON
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Im9hdXRoLWhzMjU2In0…",
  "token_type": "Bearer",
  "expires_in": 900,
  "refresh_token": "XvRKyG5Pkplrd3xkRNaEayKkpkebEMdFn0h1VIuqixAOXybMtJfK8w",
  "scope": "full"
}

O token de acesso dura 15 minutos (expires_in é em segundos). Trate-o como uma string opaca: não o interprete nem dependa do conteúdo dele.

Chamar a API

Use o token de acesso como bearer token na API REST e no servidor MCP, exatamente como uma chave de API:

Terminal
curl https://api.emailit.com/v2/domains \
  -H "Authorization: Bearer $ACCESS_TOKEN"

As requisições REST são executadas no workspace padrão da autorização: aquele por onde o usuário escolheu começar ou para o qual ele mudou depois. As ferramentas MCP também podem usar outro workspace permitido com o argumento workspace. Toda requisição usa o escopo concedido e o papel do usuário no workspace, então uma requisição fora do escopo, ou uma rota exclusiva de Admin chamada por um membro com o papel Member, retorna 403. Se o usuário sair de um workspace, a autorização também perde o acesso a ele.

Atualizar tokens

Antes de o token de acesso expirar, ou quando uma requisição retornar 401, obtenha um novo:

Terminal
curl https://api.emailit.com/oauth/token \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d grant_type=refresh_token \
  -d refresh_token="$REFRESH_TOKEN"
  • Rotação. Cada atualização retorna um novo refresh_token, válido por 60 dias. Guarde-o e descarte o antigo. Enquanto você atualizar dentro de 60 dias, a conexão não expira.
  • Detecção de reutilização. Se um token de atualização antigo for usado de novo mais de um minuto depois de ter sido substituído, o Emailit retorna invalid_grant (Refresh token reuse detected) e revoga a autorização inteira. O usuário então precisa autorizar de novo. Serialize as atualizações para que dois workers nunca usem o mesmo token de atualização.
  • Escopo mais restrito. Você pode passar scope para obter um token de acesso com menos escopos do que a autorização. Não é possível pedir mais.

Revogar uma autorização

Quando um usuário desconectar o Emailit da sua aplicação, revogue a autorização com o token de atualização dela:

Terminal
curl https://api.emailit.com/oauth/revoke \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d token="$REFRESH_TOKEN"

O endpoint autentica o seu cliente da mesma forma que o endpoint de token e sempre retorna 200 com o corpo vazio. Revogar o token de atualização revoga a autorização inteira: os tokens de acesso dela deixam de funcionar na próxima requisição. Os tokens de acesso não podem ser revogados sozinhos; token_type_hint=access_token retorna invalid_request.

Os usuários também podem revogar o acesso da sua aplicação do lado deles, em Apps conectados no painel, ou com a API de autorizações abaixo.

Gerenciar autorizações

A API de autorizações lista e altera autorizações do lado do usuário. Ela aceita a sessão do usuário no painel ou uma chave de API Full Access:

Quem chama GET /oauth/grants POST /oauth/grants/:id/revoke PUT /oauth/grants/:id/workspaces
O usuário que conectou o app As autorizações dele em todos os workspaces Revoga a autorização inteira Altera os workspaces da autorização
Chave de API Full Access As autorizações que incluem o workspace da chave Remove o workspace da chave da autorização; a autorização é revogada quando não sobra nenhum workspace Não permitido (403)

Cada autorização da lista tem este formato:

JSON
{
  "id": "9b1f6c2e-4d3a-4f8e-9a7b-2c5d8e1f0a3b",
  "client_id": "https://chatgpt.com/oauth/client.json",
  "client": { "name": "ChatGPT", "uri": "https://chatgpt.com", "logo_uri": null },
  "default_workspace": { "id": "w3f9a1c2e", "name": "Acme" },
  "workspace_access": "selected",
  "workspaces": [{ "id": "w3f9a1c2e", "name": "Acme" }],
  "scopes": ["sending", "full"],
  "resource": "https://api.emailit.com/mcp",
  "created_at": "2026-10-01T09:30:12Z",
  "revoked_at": null,
  "revoked_reason": null
}

Para alterar os workspaces de uma autorização, envie access (all ou selected), workspace_ids para selected e um default_workspace_id opcional, que deve ser um dos workspaces permitidos:

Terminal
curl -X PUT https://api.emailit.com/oauth/grants/9b1f6c2e-4d3a-4f8e-9a7b-2c5d8e1f0a3b/workspaces \
  -H "Authorization: Bearer $DASHBOARD_SESSION" \
  -H "Content-Type: application/json" \
  -d '{ "access": "selected", "workspace_ids": ["w3f9a1c2e"], "default_workspace_id": "w3f9a1c2e" }'

O usuário deve ser membro de todos os workspaces que selecionar. Uma autorização revogada não pode ser editada (409); o app precisa se conectar de novo.

Erros

Os endpoints OAuth retornam erros no formato OAuth, não no formato de erro da API REST:

JSON
{
  "error": "invalid_grant",
  "error_description": "Authorization code has expired"
}
Erro Status Quando
invalid_request 400 Um parâmetro está ausente ou é inválido, o cliente é desconhecido na autorização, a redirect_uri não está registrada, code_challenge_method não é S256 ou um segredo do cliente foi enviado tanto no cabeçalho quanto no corpo.
invalid_client 401 O endpoint de token ou de revogação não consegue autenticar o cliente: cliente desconhecido, segredo ausente ou errado.
invalid_grant 400 O código é inválido, já foi usado ou expirou; a redirect_uri ou o verifier PKCE não corresponde; ou o token de atualização é inválido, expirou, foi revogado ou reutilizado.
invalid_scope 400 O escopo não é aceito, não foi registrado para o cliente ou excede a autorização na atualização.
unsupported_response_type 400 response_type não é code.
unsupported_grant_type 400 grant_type não é authorization_code nem refresh_token.
access_denied Redirecionamento O usuário selecionou Deny.
too_many_requests 429 Mais de 20 registros por hora a partir de um endereço IP.
server_error 500 Algo deu errado do lado do Emailit. Tente de novo.

Até que client_id e redirect_uri sejam validados, os erros de autorização são exibidos como JSON no navegador e nunca redirecionados. Depois disso, os erros são redirecionados para o seu callback (com error, error_description, state e iss) apenas para URIs de redirecionamento de loopback e de uso privado e para clientes com documento de metadados; os outros clientes recebem uma página de erro em JSON. O Deny de um usuário é sempre redirecionado.

Checklist de segurança

  • Mantenha o client_secret e os tokens de atualização no seu servidor, criptografados em repouso. Nunca inclua um segredo de cliente em um app mobile, de desktop ou de navegador; use um cliente público com PKCE.
  • Gere um novo state e um novo code verifier para cada autorização e confira state e iss no callback.
  • Registre URIs de redirecionamento exatas. Não use redirecionadores abertos como callbacks.
  • Guarde cada autorização junto com o workspace a que ela pertence e trate invalid_grant pedindo ao usuário que se conecte de novo.
  • Solicite sending se você só envia e-mails.
Autorizações, duração dos tokens e revogação.
Os endpoints que os seus tokens podem chamar.
Para os seus próprios scripts, as chaves são mais simples.
O fluxo OAuth na prática.

Esta página foi útil?

Obrigado pelo feedback.

Obrigado, lemos todas as mensagens.