OAuth 2.1

É assim que um aplicativo pede autorização a uma pessoa para acessar os dados dela no CrazyLeads. A pessoa autoriza na tela do CrazyLeads, escolhendo o projeto, e pode revogar quando quiser — o aplicativo nunca recebe a senha dela.

Descoberta

Todos os endereços saem de um documento só. Leia ele em vez de escrever as URLs na mão: quando algo mudar, seu cliente acompanha sozinho.

GET https://crazyleads.com.br/api/well-known/oauth-authorization-server

De lá saem o endereço de autorização, o de token, o de registro, o de introspecção e o de revogação, além dos escopos disponíveis. Hoje o único método de desafio aceito é S256 e o único tipo de resposta é code.

1. Registrar o aplicativo

O registro é dinâmico: seu aplicativo se cadastra sozinho e recebe um client_id. Não há segredo de cliente — a segurança do fluxo vem do PKCE, e é por isso que ele é obrigatório.

POST /api/oauth/register
{
  "client_name": "Meu Aplicativo",
  "client_uri": "https://meuapp.com.br",
  "logo_uri": "https://meuapp.com.br/logo.png",
  "redirect_uris": ["https://meuapp.com.br/callback"],
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"],
  "token_endpoint_auth_method": "none"
}

Registre uma vez e guarde o client_id: o registro aceita 10 chamadas por hora por endereço de origem, e um cliente novo a cada execução esgota essa cota e ainda faz a pessoa ver um aplicativo desconhecido na tela de autorização. O nome e o logotipo que você enviar são exatamente os que ela vai ver.

2. Mandar a pessoa autorizar

Gere um code_verifier aleatório, guarde-o, e mande o desafio — o SHA-256 dele em base64url — na URL. Abra essa URL no navegador da pessoa.

GET /oauth/authorize
https://crazyleads.com.br/oauth/authorize
  ?client_id=SEU_CLIENT_ID
  &redirect_uri=https://meuapp.com.br/callback
  &response_type=code
  &state=UM_VALOR_ALEATORIO_SEU
  &code_challenge=BASE64URL_DO_SHA256_DO_VERIFIER
  &code_challenge_method=S256
  &scope=mcp:read mcp:write

O state é obrigatório: guarde-o e confira na volta, senão você aceita um retorno que não foi você quem começou. A pessoa vê o nome do seu aplicativo, o que ele vai poder fazer e escolhe o projeto. Se ela recusar, você recebe access_denied — trate isso como resposta normal, não como falha.

Na volta chega também o parâmetro iss. Confira que ele é o emissor esperado antes de usar o código.

3. Trocar o código por um token

O corpo vai como formulário, não como JSON. O código vale 10 minutos e serve uma única vez.

POST /api/oauth/token
curl -X POST https://crazyleads.com.br/api/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d grant_type=authorization_code \
  -d code=O_CODIGO_QUE_VOLTOU \
  -d client_id=SEU_CLIENT_ID \
  -d redirect_uri=https://meuapp.com.br/callback \
  -d code_verifier=O_VERIFIER_QUE_VOCE_GUARDOU
O queValidade
Código de autorização10 minutos, uso único
Token de acesso1 hora
Token de renovação90 dias, e gira a cada uso

4. Renovar — leia esta parte com atenção

Cada renovação devolve um token de renovação novo e invalida o anterior. Guardar o novo faz parte da renovação, não é detalhe de implementação.

POST /api/oauth/token
curl -X POST https://crazyleads.com.br/api/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d grant_type=refresh_token \
  -d refresh_token=SEU_TOKEN_DE_RENOVACAO \
  -d client_id=SEU_CLIENT_ID

Reenviar um token de renovação já usado revoga a cadeia inteira. Todos os tokens daquela autorização morrem na hora e a pessoa precisa autorizar de novo. É uma proteção contra token roubado — mas ela também dispara sozinha quando duas instâncias do seu aplicativo renovam ao mesmo tempo, ou quando uma renovação falha no meio e você tenta de novo com o token antigo. Grave o token novo antes de usá-lo, e deixe uma renovação por vez.

5. Usar o token

O token vai no cabeçalho Authorization. Hoje a porta de entrada para dados com este token é o servidor MCP.

curl https://crazyleads.com.br/mcp \
  -H "Authorization: Bearer SEU_TOKEN_DE_ACESSO"

Os escopos disponíveis são mcp:read, para ler, e mcp:write, para criar, editar e apagar. Peça só o que o seu aplicativo usa: a pessoa vê a diferença na tela, e pode desmarcar a escrita.

Revogar e conferir

POST /api/oauth/revoke encerra um token. Chame ao desconectar a conta no seu produto — deixar token vivo depois que a pessoa saiu é o tipo de coisa que aparece numa auditoria. POST /api/oauth/introspect diz se um token ainda vale e com quais escopos. A pessoa também pode revogar pelo CrazyLeads, a qualquer momento e sem avisar você: trate 401 como estado normal e reconduza ao fluxo de autorização em vez de repetir a chamada.

Quando dá errado

RespostaO que costuma ser
invalid_grant · code already usedO código foi trocado duas vezes — por retry automático, quase sempre.
invalid_grant · code expiredPassaram-se mais de 10 minutos entre autorizar e trocar.
invalid_grant · PKCE verification failedO verifier não corresponde ao desafio enviado, ou foi gerado outra vez no caminho.
invalid_grant · redirect_uri mismatchA URL de retorno na troca difere, mesmo que só por barra final, da que foi usada ao autorizar.
invalid_grant · replay detectedToken de renovação reutilizado. A cadeia foi revogada; refaça a autorização.
invalid_requestFalta parâmetro, ou o corpo não foi enviado como formulário.