OAuth para clientes MCP customizados
Se você está construindo seu próprio cliente MCP (CLI, SDK, plugin de IDE), esta página descreve nossa implementação OAuth: padrões que suportamos, endpoints, regras de redirect_uri e como depurar erros comuns. Usuários do Claude.ai e ChatGPT não precisam desta página — use o Quickstart no lugar.
Padrões que implementamos
mcp-telegram.com está totalmente em conformidade com as especificações OAuth nas quais o ecossistema MCP se baseia — sem extensões proprietárias, sem segredos compartilhados embutidos nos clientes.
- RFC 6749 — OAuth 2.0 Authorization Framework — authorization code grant base com refresh tokens
- RFC 7591 — Dynamic Client Registration — qualquer cliente pode se registrar em /oauth/register sem coordenação prévia
- RFC 7636 — PKCE (Proof Key for Code Exchange) — challenge S256 obrigatório para clientes públicos
- RFC 8252 — OAuth 2.0 for Native Apps — redirect URIs com IP loopback e flexibilidade de porta efêmera
- RFC 8414 — OAuth 2.0 Authorization Server Metadata — documento de discovery em /.well-known/oauth-authorization-server
- RFC 9728 — OAuth 2.0 Protected Resource Metadata — discovery do limite do recurso MCP
Endpoints
Authorization code flow com PKCE
Fluxo padrão RFC 6749 §4.1 + RFC 7636. Sem surpresas — se sua biblioteca OAuth lida com "authorization code + PKCE", vai funcionar.
Registre seu cliente
POST /oauth/register com { redirect_uris: ["http://127.0.0.1:<porta>/callback"], client_name: "nome-do-seu-cliente" }. O servidor retorna client_id + client_secret (o secret é opcional para clientes PKCE públicos, mas não atrapalha recebê-lo).
Gere o par PKCE
Gere um code_verifier aleatório de 43-128 caracteres, depois calcule code_challenge = BASE64URL(SHA256(code_verifier)). Guarde o verifier localmente para o passo 4.
Abra /oauth/authorize no navegador
Redirecione o usuário para /oauth/authorize?response_type=code&client_id=...&redirect_uri=...&state=...&code_challenge=...&code_challenge_method=S256. O servidor exibe um QR code; o usuário escaneia no app do Telegram para autenticar.
Receba o authorization code
Depois do scan do QR, o servidor redireciona para seu redirect_uri com ?code=...&state=.... Verifique se o parâmetro state bate com o que você enviou.
Troque o code por um token
POST /oauth/token com grant_type=authorization_code, code, redirect_uri, code_verifier, client_id. Você recebe um access_token (TTL de 10 anos — veja Token lifetime abaixo) e um refresh_token. Use o access_token como Authorization: Bearer ... nas requisições para /mcp.
Regras de matching de redirect_uri
Seguimos rigorosamente o RFC 8252 §7.3 e §8.4. O algoritmo de matching depende de o URI registrado ser ou não um literal de IP loopback.
Loopback (http://127.0.0.1 ou http://[::1])
Se você registrou um URI loopback, o redirect_uri no momento do authorize precisa bater exatamente em scheme, host, path e query — mas a porta pode ser diferente. Isso é exigido pelo RFC 8252 §7.3 porque clientes nativos vinculam uma porta efêmera atribuída pelo SO que pode mudar entre execuções.
- Registrado http://127.0.0.1:36201/callback bate com http://127.0.0.1:50000/callback no authorize ✅
- Registrado http://127.0.0.1:36201/callback NÃO bate com http://127.0.0.1:50000/different-path — o path tem que ser exato
- Registrado http://[::1]:36201/cb NÃO bate com http://127.0.0.1:36201/cb — loopback IPv4 e IPv6 são identificadores separados
HTTPS (https://seu-dominio.example/...)
Correspondência byte-a-byte exata, incluindo path, query e porta (RFC 6749 §3.1.2). Sem flexibilidade.
localhost (NÃO recomendado)
Tratamos http://localhost como um hostname comum — match exato obrigatório, sem flexibilidade de porta. O RFC 8252 §8.3 recomenda usar literais de IP (127.0.0.1 / [::1]) em vez de localhost porque a resolução de DNS depende da implementação.
PKCE é obrigatório
code_challenge_method=S256 é obrigatório em toda requisição de authorize. O method plain é rejeitado. Se você pular code_challenge por completo, a troca em /token vai falhar na validação do code_verifier.
Tempo de vida do token
O TTL do access_token é intencionalmente longo (10 anos) porque alguns clientes MCP não persistem o refresh_token de forma confiável. Um refresh_token ainda é emitido e rotaciona a cada refresh (RFC 6819 §5.2.2.3). O usuário pode revogar todos os tokens a qualquer momento em /my/sessions ou fazendo logout do Telegram. O usuário também pode fazer POST explícito em /oauth/revoke (RFC 7009) para encerrar a sessão.
Erros comuns
HTTP 400 "Invalid redirect_uri" em /oauth/authorize
O parâmetro redirect_uri não bate com nenhum URI registrado para esse client_id. Para clientes loopback: confira que scheme + host + path + query batem exatamente (só a porta é flexível). Para clientes HTTPS: igualdade byte-a-byte total é obrigatória — cuidado com barras finais e diferenças de URL-encoding.
HTTP 400 "Unknown client"
O client_id não existe em nosso banco. Ou você pulou o passo /oauth/register, ou a resposta do registro se perdeu antes de você salvar o client_id, ou o cliente foi revogado pelo usuário via /my/clients.
Cliente fica mostrando "Needs Auth" toda hora
Se seu cliente persiste o access_token mas não o refresh_token, você vai ver isso quando o access_token expirar. Nossos access tokens têm TTL de 10 anos justamente para mitigar isso, mas se seu cliente expira tokens do lado dele numa janela menor, você precisa ou persistir o refresh_token ou chamar /oauth/revoke + reautenticar sob demanda.
Clientes testados
Confirmado que interoperam com nosso servidor. Se você construir algo novo e funcionar, manda um PR para a gente adicionar aqui.
- Claude.ai web — via conector MCP nativo
- ChatGPT Apps — via conector MCP nativo
- Hermes Agent — cliente MCP CLI open-source (RFC 8252 loopback flow)
- Cursor MCP — plugin de IDE (RFC 8252 loopback flow)
- Qualquer cliente compatível com RFC 6749 + RFC 7591 + RFC 7636 + RFC 8252 deve funcionar sem mudanças de código do nosso lado.
Múltiplas contas Telegram em uma única conexão OAuth
A partir da v2.32.0, uma única conexão OAuth pode manter várias identidades do Telegram e alternar entre elas com uma chamada de ferramenta — sem ciclo de Disconnect/Connect, sem registrar um novo cliente.
Listar o que está vinculado
Chame telegram-accounts-list. Você verá sua conta primary (vinculada ao OAuth) marcada com ⭐ se estiver ativa, além de quaisquer contas secundárias que você tenha adicionado.
Vincular outra conta
Chame telegram-accounts-add com um label opcional (ex.: "testing"). A ferramenta retorna uma URL de uso único (TTL 10 minutes) — abra-a em qualquer dispositivo e escaneie o QR com a conta Telegram que você quer adicionar.
Alternar a conta ativa
Chame telegram-accounts-switch com identifier=label, @username, account_id ou 'primary'. A próxima chamada telegram-* já usa essa conta imediatamente. Sem reconectar.
Desvincular uma conta secundária
Chame telegram-accounts-remove identifier=… em uma conta secundária. A conta Telegram em si NÃO é deslogada — apenas o vínculo aqui é removido. A conta primary não pode ser removida desta forma; use o fluxo de Disconnect do seu cliente para sair completamente.
Cada conexão OAuth é isolada: contas que você vincula via Hermes ficam invisíveis para Claude.ai ou ChatGPT, mesmo que seja a mesma identidade Telegram. Para conectar contas diferentes a clientes MCP diferentes, registre cada cliente separadamente e use telegram-accounts-add dentro da sessão de cada um.