Sécuriser les serveurs MCP : OAuth, liaison d'audience et le député confus
- Comprendre pourquoi un serveur MCP distant (HTTP) est un serveur de ressources OAuth 2.1, et pas seulement un point d'accès à clé API
- Suivre le handshake de découverte : 401 → Protected Resource Metadata → Authorization Server Metadata → jeton
- Expliquer la liaison d'audience des jetons (RFC 8707) et pourquoi elle empêche le jeton d'un service de fonctionner sur un autre
- Nommer le piège du député confus et l'unique règle qui le referme : ne jamais transférer le jeton d'un client vers une API en amont
- Appliquer une courte liste de durcissement avant d'exposer un serveur MCP sur Internet
MCP est passé de curiosité à la manière par défaut dont les agents atteignent les outils — ce qui signifie que les serveurs MCP se trouvent désormais devant des données réelles et des actions réelles. Un serveur local que vous lancez via STDIO fait confiance à son environnement : il lit les identifiants depuis les variables d'environnement et il n'y a aucune frontière réseau à défendre. Dès l'instant où vous rendez ce même serveur distant (HTTP), quiconque peut atteindre l'URL peut tenter de l'appeler. Cela le transforme en un problème d'autorisation, et la spécification MCP y répond avec OAuth 2.1 — pas avec un schéma de clé API sur mesure.
Cette page concerne le cas distant. Si votre serveur est uniquement STDIO, la spécification dit explicitement de ne pas suivre le flux OAuth — récupérez les identifiants depuis l'environnement et passez à autre chose.
Les trois rôles
OAuth découpe le problème en trois parties. MCP s'y projette proprement :
Le glissement mental clé : le serveur MCP ne gère jamais lui-même la connexion. Il ne fait que valider des jetons émis par quelqu'un d'autre. C'est cette séparation qui vous permet de placer un fournisseur d'identité prêt à l'emploi devant un serveur que vous avez écrit.
Le handshake de découverte
Un client ne devrait pas avoir besoin d'être préconfiguré avec l'endroit où s'authentifier. MCP rend la découverte automatique, pilotée par un 401 :
- La toute première requête part à nu. Le serveur la rejette avec HTTP 401 Unauthorized et un en-tête WWW-Authenticate pointant vers son URL de resource-metadata.
- Il fait un GET sur /.well-known/oauth-protected-resource du serveur. Le champ authorization_servers du document nomme au moins un serveur d'autorisation que le client peut utiliser.
- Il fait un GET sur /.well-known/oauth-authorization-server de l'AS pour connaître les points d'accès authorize et token ainsi que les capacités prises en charge.
- Si le client n'a pas d'identifiant client pour cet AS, il peut faire un POST sur /register pour en obtenir un sans intervention humaine — crucial car un client ne peut pas connaître tous les serveurs MCP à l'avance.
- Le client génère un vérificateur/défi PKCE, ouvre le navigateur sur l'URL authorize incluant le paramètre resource, l'utilisateur donne son consentement, et le client échange le code renvoyé (avec le vérificateur) contre un jeton d'accès.
- Désormais chaque requête porte Authorization: Bearer <token>. Le serveur le valide et répond.
Remarquez qu'il n'y a aucune config d'authentification codée en dur du côté client — le 401 amorce tout. C'est tout l'intérêt : un agent peut se connecter à un serveur qu'il n'a jamais vu et déterminer comment s'authentifier.
Liaison d'audience : la règle porteuse
Voici le mode de défaillance que la liaison d'audience existe pour empêcher. Disons qu'un utilisateur possède un jeton émis pour calendar.example.com. Un serveur MCP malveillant (ou simplement négligent) à evil.example.com trompe le client pour qu'il lui envoie ce jeton. Si evil l'accepte, il peut désormais se retourner et appeler l'API du calendrier en tant que l'utilisateur. Le jeton d'un service a fonctionné sur un autre. La frontière de sécurité d'OAuth vient de s'effondrer.
Le correctif, ce sont les Resource Indicators (RFC 8707) :
- À la fois sur la requête d'autorisation et sur la requête de jeton, le client DOIT inclure un paramètre resource fixé à l'URI canonique du serveur MCP qu'il compte appeler — par ex. resource=https://mcp.example.com. Il l'envoie même s'il n'est pas sûr que l'AS le prenne en charge.
- Lorsqu'il est pris en charge, l'AS estampille le jeton pour qu'il ne soit valide que pour ce serveur de ressources précis.
- Avant tout travail, le serveur MCP DOIT vérifier que le jeton a été émis pour LUI — en contrôlant la revendication d'audience (RFC 9068). Un jeton frappé pour quelqu'un d'autre reçoit un 401, point final.
Paramètre resource sur la requête d'autorisation (encodé en URL)
&resource=https%3A%2F%2Fmcp.example.com
Les URI canoniques sont strictes : https://mcp.example.com et https://mcp.example.com:8443/mcp sont valides ; mcp.example.com (sans schéma) et https://mcp.example.com#frag (fragment) ne le sont pas. Préférez la forme sans barre oblique finale pour l'interopérabilité.
Le député confus : ne jamais transférer le jeton
C'est l'erreur qui transforme un serveur MCP bien intentionné en proxy pour un attaquant. C'est le même problème du député confus issu de la sécurité des agents, affûté en une règle concrète.
Un serveur MCP a souvent besoin d'appeler une API en amont (GitHub, un service de base de données, un autre SaaS). La tentation est de prendre le jeton que le client vous a remis et de le transférer en amont. Ne le faites pas. La spécification est catégorique : le serveur MCP NE DOIT PAS transférer le jeton qu'il a reçu du client.
Pourquoi c'est dangereux : le jeton du client a été émis pour votre serveur comme audience. Si vous le transférez, l'API en amont peut lui faire confiance comme s'il venait de vous, ou supposer que vous l'avez déjà validé — et voilà qu'un jeton limité à un saut effectue du travail deux sauts plus loin, hors du modèle de consentement de qui que ce soit.
- Si votre serveur MCP appelle une API en amont, il agit comme un client OAuth DISTINCT vis-à-vis de cette API et obtient son PROPRE jeton auprès du serveur d'autorisation en amont. Deux jetons indépendants, deux audiences indépendantes. Le jeton du client s'arrête à votre porte.
Une liste de durcissement pré-vol
Avant qu'un serveur MCP distant touche l'Internet public :
- Tous les points d'accès de l'AS DOIVENT être en HTTPS. Les redirect URIs DOIVENT être en HTTPS ou localhost — rien d'autre.
- Rejetez tout jeton non émis spécifiquement pour ce serveur. C'est l'unique contrôle qui stoppe la réutilisation inter-services des jetons.
- Les clients DOIVENT utiliser PKCE pour qu'un code d'autorisation intercepté soit inutile sans le vérificateur correspondant.
- L'AS DOIT faire correspondre les redirect URIs exactement à des valeurs préenregistrées, et les clients DEVRAIENT utiliser et vérifier le paramètre state — les deux défendent contre le phishing par open-redirect.
- Émettez des jetons d'accès de courte durée pour limiter les dégâts d'une fuite ; pour les clients publics, faites tourner les refresh tokens. Stockez les jetons de façon sécurisée et ne les journalisez jamais.
- Les jetons vont dans l'en-tête Authorization, jamais dans la query string, où ils atterriraient dans les journaux et les referrers.
- La liaison d'audience est le portail de transport ; appliquez tout de même le moindre privilège, le sandboxing et l'humain dans la boucle depuis /docs/security/securing-agents. L'authentification dit QUI — elle ne dit pas que la requête est sûre.
Vérifiez vos acquis
Vérifiez vos acquis
0/4Sources et lectures complémentaires
- Spécification d'autorisation MCP (2025-06-18) — le flux normatif, les rôles et les exigences MUST/SHOULD que cette page résume.
- MCP Security Best Practices — transfert de jeton, député confus, et pourquoi ils sont interdits.
- RFC 8707 — Resource Indicators for OAuth 2.0 — le paramètre
resourceet la liaison d'audience. - RFC 9728 — OAuth 2.0 Protected Resource Metadata — comment un serveur de ressources annonce ses serveurs d'autorisation.
- RFC 8414 — OAuth 2.0 Authorization Server Metadata et RFC 7591 — Dynamic Client Registration.
- OAuth 2.1 draft — PKCE, sécurité des communications et exigences de gestion des jetons.
- En lien sur AILmanac : Sécuriser les agents et les outils · Injection de prompt · MCP dans Claude Code.