MCP Fusion/Security and governance/Autenticação

Autenticação

Pergunte à IA sobre a Vinkius

Três pacotes de autenticação para conectores: verificação de JWT com JWKS, chaves de API com comparação segura no tempo e o fluxo de autorização de dispositivo OAuth 2.0 transformado em ferramentas que o agente pode conduzir.

Um conector que atua na conta de alguém precisa saber quem está fazendo a solicitação. O MCP Fusion oferece três pacotes de autenticação, cada um com um middleware e uma ferramenta de autenticação opcional, para que o agente possa ser bloqueado, desafiado e depois liberado sem que o seu handler saiba a diferença.

De onde vem a identidade

A autenticação lê a identidade de ctx, e ctx é criado por requisição por contextFactory. A configuração canônica:

typescript
registry.attachToServer(server, {
  contextFactory: async (extra) => ({
    token: extra.session?.authToken ?? '',
    headers: extra.headers ?? {},
  }),
});

Tudo abaixo lê esse contexto.

JWT

bash
npm install @mcpfusion/jwt
typescript
import { requireJwt } from '@mcpfusion/jwt';

f.query('billing.list_invoices')
  .use(requireJwt({
    jwksUri: 'https://auth.example.com/.well-known/jwks.json',
    issuer: 'https://auth.example.com/',
    audience: 'my-connector',
    requiredClaims: ['sub', 'tenant_id'],
    onVerified: (ctx, payload) => {
      ctx.tenantId = payload.tenant_id;   // derived identity for the handler
    },
  }))
  .handle(async (input, ctx) => listInvoices(ctx.tenantId));

JwtVerifier aceita secret (HS256), publicKey (PEM) ou jwksUri (conjunto de chaves remoto, armazenado em cache por verificador). Com jose instalado, RS256, ES256 e JWKS funcionam; sem ele, um caminho nativo HS256 verifica com timingSafeEqual e recusa qualquer outro algoritmo. issuer, audience, clockTolerance (60 segundos) e requiredClaims são validados em cada token. verifyDetailed() retorna { valid, payload, reason } quando você quer o motivo em vez de null.

Ordem padrão de extração do token: ctx.token, depois ctx.jwt, depois ctx.headers.authorization (o prefixo Bearer é removido). As falhas retornam um toolError autocurável com o código JWT_INVALID e uma ação auth para recuperação.

O pacote JWT verifica tokens, mas não os atualiza. O código-fonte não oferece suporte a refresh token, então um conector que precise de acesso duradouro a um provedor deve usar o fluxo OAuth abaixo ou o cofre de credenciais.

A ferramenta opcional createJwtAuthTool() expõe verify e status como ações que o agente pode chamar quando o próprio cliente mantém o token.

Chaves de API

bash
npm install @mcpfusion/api-key
typescript
import { requireApiKey } from '@mcpfusion/api-key';

f.mutation('billing.refund')
  .use(requireApiKey({
    keys: [process.env.SERVICE_KEY!],
    onValidated: (ctx) => { ctx.service = 'billing-service'; },
  }))
  .handle(...);

As chaves podem ser texto simples, com hash interno por SHA-256 na construção, ou pré-hash, ou podem ser validadas pela sua função assíncrona validator. A ordem das verificações é: não vazia, minLength (16 por padrão), prefix opcional e depois o validador ou o conjunto de hashes. A ordem de extração é: ctx.apiKey, ctx.headers['x-api-key'] e então ctx.headers.authorization (os prefixos ApiKey e Bearer são removidos).

A comparação busca ser constante no tempo: o gerenciador compara hashes de uma forma que não interrompe no primeiro byte diferente. Não trate o comprimento da chave como um segredo.

Fluxo de dispositivo OAuth para o agente

Quando o conector precisa de uma conta que o agente ainda não possui, o fluxo precisa ser conduzido por uma conversa: o servidor entrega um código e uma URL, a pessoa aprova no navegador e o agente pergunta novamente. Esse é o RFC 8628, e o pacote o transforma em ferramentas:

bash
npm install @mcpfusion/oauth
typescript
import { createAuthTool, requireAuth } from '@mcpfusion/oauth';

const auth = createAuthTool({
  clientId: process.env.OAUTH_CLIENT_ID!,
  authorizationEndpoint: 'https://auth.example.com/device/code',
  tokenEndpoint: 'https://auth.example.com/device/token',
  onAuthenticated: (token) => { /* cache or forward the token */ },
});

f.query('analytics.report')
  .use(requireAuth())          // blocks with AUTH_REQUIRED until a token exists
  .handle(...);

A ferramenta expõe quatro ações:

ActionBehavior
loginsolicita um código de dispositivo e retorna a URL de verificação e o código
completetroca o código uma vez; authorization_pending significa "ainda não, pergunte novamente"
statusinforma se existe um token e, opcionalmente, a qual usuário ele pertence
logoutlimpa o token

O loop de consulta respeita o RFC 8628: a primeira consulta é imediata, authorization_pending continua, slow_down adiciona cinco segundos, qualquer outro erro termina com a descrição do próprio provedor e o prazo lança "Device authorization expired. Start a new flow." O verificador não envia um scope por você e não há atualização automática: o armazenamento do token é um arquivo no diretório pessoal (.mcpfusion/token.json, modo 0600, com fallback para icacls no Windows), portanto trate-o como o padrão local de usuário único e configure sua própria persistência para um conector hospedado.

requireAuth() verifica a presença de um token, não a sua validade. Combine-o com requireJwt quando o token upstream precisar ser verificado criptograficamente.

Notas de produção

  • Prefira credenciais da plataforma a tokens de usuário para chamadas servidor a servidor: declare-as com defineCredentials e leia-as com requireCredential. Consulte Credentials.
  • No Vinkius Cloud, invoque com um token de conexão e use Connection Tokens no console para revogar o acesso por cliente.
  • O middleware de autenticação compõe com o restante da cadeia: coloque-o na camada mais externa para que chamadas não autorizadas nunca cheguem à validação, como mostrado em Middleware and context.

Próximos passos