MCP Fusion/Security and governance/Authentification
Authentification
Trois packages d’authentification pour les connecteurs : vérification JWT avec JWKS, clés d’API à comparaison résistante au temps et flux d’autorisation par appareil OAuth 2.0 transformé en outils pilotables par l’agent.
Un connecteur qui agit sur le compte de quelqu’un doit savoir qui fait la demande. MCP Fusion fournit trois packages d’authentification, chacun avec un middleware et un outil d’authentification facultatif, afin que l’agent puisse être bloqué, mis au défi puis débloqué sans que votre handler voie la différence.
D’où vient l’identité
L’authentification lit l’identité dans ctx, et ctx est créé pour chaque requête par contextFactory. Le câblage canonique :
registry.attachToServer(server, {
contextFactory: async (extra) => ({
token: extra.session?.authToken ?? '',
headers: extra.headers ?? {},
}),
});Tout ce qui suit lit ce contexte.
JWT
npm install @mcpfusion/jwtimport { 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 accepte secret (HS256), publicKey (PEM) ou jwksUri (ensemble de clés distant, mis en cache par vérificateur). Avec jose installé, RS256, ES256 et JWKS fonctionnent ; sans lui, un chemin natif HS256 vérifie avec timingSafeEqual et refuse tout autre algorithme. issuer, audience, clockTolerance (60 secondes) et requiredClaims sont validés sur chaque jeton. verifyDetailed() renvoie { valid, payload, reason } lorsque vous voulez la raison plutôt que null.
Ordre d’extraction par défaut du jeton : ctx.token, puis ctx.jwt, puis ctx.headers.authorization (le préfixe Bearer est retiré). Les échecs renvoient un toolError auto-réparable avec le code JWT_INVALID et une action auth pour récupérer l’accès.
Le package JWT vérifie les jetons, mais ne les renouvelle pas. Le code source ne prend pas en charge les refresh tokens. Un connecteur qui a besoin d’un accès durable au fournisseur doit donc utiliser le flux OAuth ci-dessous ou le coffre de credentials.
L’outil facultatif createJwtAuthTool() expose verify et status comme actions appelables par l’agent lorsque le client détient lui-même le jeton.
Clés d’API
npm install @mcpfusion/api-keyimport { requireApiKey } from '@mcpfusion/api-key';
f.mutation('billing.refund')
.use(requireApiKey({
keys: [process.env.SERVICE_KEY!],
onValidated: (ctx) => { ctx.service = 'billing-service'; },
}))
.handle(...);Les clés peuvent être en clair, hachées en interne avec SHA-256 lors de la construction, pré-hachées ou validées par votre fonction asynchrone validator. L’ordre des vérifications est le suivant : non vide, minLength (16 par défaut), prefix facultatif, puis le validateur ou l’ensemble de hachages. L’ordre d’extraction est : ctx.apiKey, ctx.headers['x-api-key'], puis ctx.headers.authorization (les préfixes ApiKey et Bearer sont retirés).
La comparaison vise un temps constant : le gestionnaire compare les hachages sans s’arrêter au premier octet différent. Ne considérez pas la longueur de la clé comme un secret.
Flux d’appareil OAuth pour l’agent
Lorsque le connecteur a besoin d’un compte que l’agent ne possède pas encore, le flux doit pouvoir être piloté depuis une conversation : le serveur remet un code et une URL, la personne approuve dans un navigateur, puis l’agent redemande. C’est le RFC 8628, et le package le transforme en outils :
npm install @mcpfusion/oauthimport { 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(...);L’outil expose quatre actions :
| Action | Comportement |
|---|---|
login | demande un code d’appareil et renvoie l’URL de vérification et le code |
complete | échange le code une fois ; authorization_pending signifie « pas encore, demandez à nouveau » |
status | indique si un jeton existe et, facultativement, à quel utilisateur il appartient |
logout | efface le jeton |
La boucle d’interrogation respecte le RFC 8628 : le premier sondage est immédiat, authorization_pending continue, slow_down ajoute cinq secondes, toute autre erreur se termine avec la description du fournisseur et l’échéance lève "Device authorization expired. Start a new flow." Le vérificateur n’envoie pas de scope pour vous et il n’y a pas de renouvellement automatique : le stockage du jeton est un fichier dans le répertoire personnel (.mcpfusion/token.json, mode 0600, avec un repli icacls sous Windows). Considérez-le comme le défaut local mono-utilisateur et prévoyez votre propre persistance pour un connecteur hébergé.
requireAuth() vérifie la présence d’un jeton, pas sa validité. Associez-le à requireJwt lorsque le jeton amont doit être vérifié cryptographiquement.
Notes de production
- Préférez les credentials de la plateforme aux jetons utilisateur pour les appels serveur à serveur : déclarez-les avec
defineCredentialset lisez-les avecrequireCredential. Consultez Credentials. - Sur Vinkius Cloud, invoquez avec un jeton de connexion et utilisez Connection Tokens dans la console pour révoquer l’accès par client.
- Le middleware d’authentification se compose avec le reste de la chaîne : placez-le à l’extérieur afin que les appels non autorisés n’atteignent jamais la validation, comme dans Middleware and context.
Étapes suivantes
- Multi-tenant connectors : l’identité devient isolation
- Security pipeline : où se place l’authentification parmi les couches
- Credentials : secrets serveur sans jetons utilisateur
