For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
Navigation principale
Theme
Vue d’ensemble Documentation utilisateur de ChatGPT et Codex Cas d’usage

Authentification

Méthodes d’authentification pour les serveurs MCP de plugins.

Authentifiez vos utilisateurs

De nombreux serveurs MCP de plugins peuvent fonctionner en mode anonyme et en lecture seule. En revanche, tout serveur qui donne accès à des données propres à un client ou à des opérations d’écriture devrait authentifier les utilisateurs.

Les plugins publiés peuvent fonctionner dans ChatGPT et Codex. Le contrat d’autorisation MCP s’applique aux deux produits. Ce guide précise les particularités du client ChatGPT lorsqu’une URL de rappel, un document de métadonnées ou une interface de liaison de compte diffère d’un produit à l’autre.

Vous pouvez intégrer votre propre serveur d’autorisation pour vous connecter à une application existante côté serveur ou partager des données entre utilisateurs.

Authentification personnalisée avec OAuth 2.1

Si votre serveur MCP exige une authentification, vous devez mettre en œuvre un flux OAuth 2.1 conforme à la spécification d’autorisation MCP.

Composants

  • Serveur de ressources : votre serveur MCP expose les outils et vérifie les jetons d’accès à chaque requête.
  • Serveur d’autorisation : votre fournisseur d’identité ou votre propre implémentation délivre les jetons et publie les métadonnées de découverte.
  • Client : l’hôte OpenAI, par exemple ChatGPT ou Codex, agit pour le compte de l’utilisateur. Les clients pris en charge utilisent les documents de métadonnées d’identifiant client (CIMD), l’enregistrement dynamique des clients (DCR), les clients OAuth prédéfinis et PKCE.

Exigences de la spécification d’autorisation MCP

  • Hébergez les métadonnées de la ressource protégée sur votre serveur MCP.
  • Publiez les métadonnées OAuth sur votre serveur d’autorisation.
  • Reprenez le paramètre resource tout au long du flux OAuth.
  • Choisissez comment l’hôte OpenAI identifie ou enregistre son client OAuth : CIMD, DCR ou client OAuth prédéfini.
  • Publiez les méthodes d’authentification que votre serveur d’autorisation accepte au point de terminaison de jetons.

Voici comment appliquer ces exigences.

Hébergez les métadonnées de la ressource protégée sur votre serveur MCP

  • Prévoyez un point de terminaison HTTPS tel que GET https://your-mcp.example.com/.well-known/oauth-protected-resource (ou indiquez cette même URL dans l’en-tête WWW-Authenticate des réponses 401 Unauthorized) pour que ChatGPT sache où récupérer vos métadonnées.
  • Ce point de terminaison renvoie un document JSON qui décrit le serveur de ressources et les serveurs d’autorisation disponibles :
{
  "resource": "https://your-mcp.example.com",
  "authorization_servers": ["https://auth.yourcompany.com"],
  "scopes_supported": ["files:read", "files:write"],
  "resource_documentation": "https://yourcompany.com/docs/mcp"
}
  • Renseignez les champs suivants en tenant compte de leur caractère obligatoire ou facultatif :
    • resource : identifiant HTTPS canonique de votre serveur MCP. Pendant le flux OAuth, ChatGPT transmet cette valeur exacte dans le paramètre de requête resource.
    • authorization_servers : une ou plusieurs URL de base d’émetteurs qui pointent vers votre fournisseur d’identité. ChatGPT essaie chacune d’elles pour trouver les métadonnées OAuth.
    • scopes_supported : liste facultative qui aide ChatGPT à expliquer à l’utilisateur les autorisations qu’il va lui demander.
    • Les champs facultatifs de la RFC 9728, tels que resource_documentation, resource_policy_uri ou resource_tos_uri, aident les clients et les administrateurs à comprendre votre configuration.

Si vous bloquez une requête faute d’authentification, renvoyez un défi d’authentification de ce type :

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://your-mcp.example.com/.well-known/oauth-protected-resource",
                         scope="files:read"

Ce seul en-tête permet à ChatGPT de découvrir l’URL des métadonnées, même lors du premier accès.

Publiez les métadonnées OAuth sur votre serveur d’autorisation

  • Votre fournisseur d’identité doit exposer l’un des documents de découverte aux adresses standard suivantes pour que ChatGPT puisse lire sa configuration :
    • Métadonnées OAuth 2.0 à l’adresse https://auth.yourcompany.com/.well-known/oauth-authorization-server
    • Métadonnées OpenID Connect à l’adresse https://auth.yourcompany.com/.well-known/openid-configuration
  • Chaque document indique à l’hôte OpenAI où rediriger l’utilisateur, comment échanger les codes et comment s’identifier. Voici une réponse type :
{
  "issuer": "https://auth.yourcompany.com",
  "authorization_response_iss_parameter_supported": true,
  "authorization_endpoint": "https://auth.yourcompany.com/oauth2/v1/authorize",
  "token_endpoint": "https://auth.yourcompany.com/oauth2/v1/token",
  "client_id_metadata_document_supported": true,
  "token_endpoint_auth_methods_supported": ["none", "private_key_jwt"],
  "registration_endpoint": "https://auth.yourcompany.com/oauth2/v1/register",
  "code_challenge_methods_supported": ["S256"],
  "scopes_supported": ["files:read", "files:write"]
}
  • Vérifiez les valeurs des champs suivants :
    • issuer : identifiant canonique du serveur d’autorisation. Utilisez cette valeur exacte dans la liste authorization_servers des métadonnées de la ressource protégée.
    • authorization_response_iss_parameter_supported : définissez ce champ sur true uniquement si votre serveur d’autorisation renvoie un paramètre iss dans chaque réponse d’autorisation, y compris en cas d’erreur.
    • authorization_endpoint, token_endpoint : URL dont ChatGPT a besoin pour exécuter de bout en bout le flux OAuth par code d’autorisation avec PKCE.
    • client_id_metadata_document_supported : définissez ce champ sur true si vous souhaitez que ChatGPT utilise CIMD pour l’enregistrement du client. ChatGPT privilégie CIMD lorsqu’il est disponible, mais le développeur du plugin peut choisir DCR si les deux méthodes sont disponibles.
    • token_endpoint_auth_methods_supported : indiquez les méthodes d’authentification que votre serveur d’autorisation accepte au point de terminaison de jetons. Ce champ s’applique à CIMD, à DCR et aux clients OAuth prédéfinis. Avec CIMD, ChatGPT prend en charge none pour les échanges de jetons par un client public et private_key_jwt pour les échanges de jetons avec une assertion client signée. Les autres clients OAuth utilisent généralement none, client_secret_post ou client_secret_basic.
    • registration_endpoint : incluez ce champ si vous prenez en charge l’enregistrement dynamique des clients (DCR). ChatGPT peut ainsi créer et réutiliser un client_id dédié à la connexion au serveur MCP.
    • code_challenge_methods_supported : ce champ doit inclure S256. Les serveurs MCP ne sont pas pris en charge si les métadonnées de leur serveur d’autorisation omettent ce champ ou n’y déclarent pas S256, comme l’exige la spécification d’autorisation MCP.
    • Les champs facultatifs suivent la RFC 8414 ou la spécification de découverte OpenID. Incluez ceux qui aideront vos administrateurs à configurer leurs politiques.

Portées OIDC

  • Si votre fournisseur déclare des portées OIDC (par exemple openid, email, profile) dans le champ scopes_supported de son document .well-known/oauth-authorization-server ou .well-known/openid-configuration, ChatGPT les demande par défaut pendant le flux OAuth.
  • Certains fournisseurs d’identité n’activent pas par défaut les portées OIDC qu’ils déclarent. Vérifiez les paramètres de votre fournisseur et assurez-vous que chaque portée déclarée est activée pour le client OAuth, qu’il utilise CIMD ou qu’il ait été créé manuellement ou via DCR.

Prenez en charge les restrictions de domaine des espaces de travail

Les espaces de travail ChatGPT Enterprise peuvent faire vérifier qu’un domaine de messagerie leur appartient. Lorsqu’un plugin lié via OAuth fournit l’adresse e-mail vérifiée de l’utilisateur, ChatGPT peut s’appuyer sur le domaine de cette adresse pour empêcher l’utilisateur de lier le plugin avec son identité professionnelle dans un espace de travail personnel ou un autre espace extérieur à l’organisation.

Pour prendre en charge cette protection, configurez votre serveur d’autorisation comme suit :

  • Publiez les métadonnées de découverte OpenID Connect.
  • Déclarez et activez les portées openid et email.
  • Déclarez un point de terminaison UserInfo qui renvoie la revendication email de l’utilisateur et email_verified: true.

Vous pouvez également renvoyer ces revendications dans un jeton d’identité pendant le flux OAuth, mais les restrictions de domaine des espaces de travail exigent un point de terminaison UserInfo.

L’espace de travail Enterprise doit également faire vérifier son domaine. Votre serveur d’autorisation fournit l’identité de l’utilisateur que ChatGPT compare aux domaines vérifiés configurés pour l’espace de travail. Il ne vérifie pas que le domaine appartient à cet espace.

Conservez le contexte de connexion lors d’une nouvelle autorisation

Lorsque ChatGPT renouvelle l’autorisation d’une liaison existante, notamment pour demander des portées OAuth supplémentaires, il peut transmettre le jeton d’identité OIDC précédent dans le paramètre standard id_token_hint de la requête d’autorisation. Pour que les utilisateurs puissent accorder des portées supplémentaires sans reprendre la procédure de connexion depuis le début, configurez votre serveur d’autorisation pour qu’il délivre un jeton d’identité lors du flux OAuth initial et tienne compte de id_token_hint lors de l’autorisation.

Cette optimisation est facultative. Le renouvellement de l’autorisation fonctionne même si aucun jeton d’identité n’est disponible ou si votre serveur d’autorisation ignore cette indication.

Protégez les rappels en identifiant l’émetteur

Les hôtes OpenAI utilisent le mécanisme d’identification de l’émetteur de la RFC 9207 pour protéger les rappels OAuth contre les attaques par confusion de serveurs d’autorisation. Pour permettre à ChatGPT et à Codex d’utiliser un URI de redirection stable lors de la création d’un client OAuth éligible :

  • Définissez authorization_response_iss_parameter_supported: true dans les métadonnées du serveur d’autorisation.
  • Utilisez exactement le même identifiant d’émetteur dans le champ issuer de ces métadonnées et dans la liste authorization_servers des métadonnées de la ressource protégée.
  • Renvoyez iss dans chaque réponse d’autorisation, qu’il s’agisse d’un succès ou d’une erreur. Sa valeur doit correspondre exactement à celle du champ issuer des métadonnées. Les clients comparent les chaînes à l’identique, sans normaliser les barres obliques finales, les chemins, les ports ni la casse.

Avant de rediriger l’utilisateur, ChatGPT et Codex enregistrent la valeur issuer des métadonnées sélectionnées. Ils vérifient ensuite la valeur iss renvoyée avant d’échanger le code d’autorisation. Si le serveur déclare prendre en charge l’identification de l’émetteur mais omet iss ou renvoie une valeur différente, ChatGPT et Codex rejettent la réponse. Ces exigences suivent les règles MCP de validation des réponses d’autorisation.

URL de redirection

Copiez à l’identique l’URI de redirection de production affiché sur la page de gestion du serveur MCP dans la liste d’autorisation de votre serveur d’autorisation.

  • Si votre serveur d’autorisation ne remplit pas les conditions d’identification de l’émetteur ci-dessus, ChatGPT utilise l’URI de redirection propre à l’identifiant de rappel, https://chatgpt.com/connector/oauth/{callback_id}.
  • Si votre serveur d’autorisation remplit ces conditions, ChatGPT utilise l’URI de redirection stable https://chatgpt.com/connector_platform_oauth_redirect.

Les serveurs MCP publiés avant que ChatGPT n’introduise les redirections propres à chaque identifiant de rappel continuent également d’utiliser l’URI de redirection stable.

Reprenez le paramètre resource tout au long du flux OAuth

  • ChatGPT ajoute resource=https%3A%2F%2Fyour-mcp.example.com aux requêtes d’autorisation et de jeton. Ce paramètre associe le jeton aux métadonnées de la ressource protégée présentées plus haut.
  • Configurez votre serveur d’autorisation pour qu’il copie cette valeur dans le jeton d’accès (généralement dans la revendication aud). Votre serveur MCP peut ainsi vérifier que le jeton a été délivré pour lui seul.
  • Si un jeton ne contient pas l’audience ou les portées attendues, rejetez-le et utilisez le défi WWW-Authenticate pour inviter ChatGPT à renouveler l’autorisation avec les bons paramètres.

Prenez en charge le flux par code d’autorisation

  • En tant que client MCP, ChatGPT exécute le flux par code d’autorisation avec PKCE et utilise la méthode de défi S256 pour empêcher un attaquant de réutiliser un code d’autorisation intercepté.
  • Votre serveur d’autorisation doit publier code_challenge_methods_supported avec la valeur S256 pour que les clients puissent vérifier la prise en charge de PKCE dans les métadonnées.

Flux OAuth

Une fois la spécification d’autorisation MCP mise en œuvre comme indiqué ci-dessus, le flux OAuth se déroule ainsi :

  1. ChatGPT interroge votre serveur MCP pour obtenir les métadonnées de la ressource protégée.

  1. ChatGPT s’identifie en tant que client OAuth. Si le serveur MCP utilise CIMD, ChatGPT ignore l’étape d’enregistrement dynamique du client et envoie l’URL d’un document CIMD comme client_id. Pour les serveurs d’autorisation qui remplissent les conditions d’identification de l’émetteur ci-dessus, ChatGPT utilise l’URL stable https://chatgpt.com/oauth/client.json. Pour les autres, il utilise l’URL propre à l’identifiant de rappel https://chatgpt.com/oauth/{callback_id}/client.json. La page de gestion du serveur MCP indique le document de métadonnées du client et l’URI de redirection exacts correspondant au mode de rappel de la connexion. Si le serveur MCP utilise DCR, ChatGPT appelle une seule fois le point de terminaison registration_endpoint de votre serveur d’autorisation pour cette connexion au serveur MCP. Il reçoit un client_id généré et réutilise ce client pour la même connexion.

Avec CIMD, il n’y a pas d’étape d’enregistrement du client. L’écran suivant illustre le parcours DCR :

  1. Lorsque l’utilisateur appelle un outil pour la première fois, le client ChatGPT lance le flux OAuth par code d’autorisation avec PKCE. L’utilisateur s’authentifie et consent aux portées demandées.

  1. ChatGPT échange le code d’autorisation contre un jeton d’accès et joint ce jeton aux requêtes MCP suivantes (Authorization: Bearer <token>).

  1. À chaque requête, votre serveur vérifie le jeton (émetteur, audience, expiration et portées) avant d’exécuter l’outil.

Enregistrement du client

Privilégiez les documents de métadonnées d’identifiant client (CIMD) pour l’enregistrement du client si votre serveur d’autorisation les prend en charge et que le développeur du plugin choisit cette méthode. Avec CIMD, ChatGPT utilise l’URL HTTPS d’un document de métadonnées comme client_id. Votre serveur d’autorisation récupère ce document, valide les métadonnées publiées du client et les URI de redirection, puis utilise l’URL du document comme identifiant stable du client ChatGPT.

Si vous prenez en charge CIMD, définissez client_id_metadata_document_supported: true dans les métadonnées de votre serveur d’autorisation. ChatGPT peut ainsi utiliser une identité client stable et commune aux serveurs MCP qui choisissent CIMD. Votre serveur d’autorisation peut s’appuyer sur cette identité pour gérer les listes d’URI de redirection autorisés, les limites de débit et d’autres politiques.

ChatGPT adopte l’évolution de CIMD proposée dans MCP SEP-3149. Son document CIMD de production publie token_endpoint_auth_methods_supported sous forme de tableau des méthodes que ChatGPT peut utiliser, sans ordre de préférence. Pendant la transition, il publie également l’ancien champ au singulier token_endpoint_auth_method pour indiquer une préférence :

{
  "token_endpoint_auth_methods_supported": ["none", "private_key_jwt"],
  "token_endpoint_auth_method": "private_key_jwt"
}

Le champ au pluriel se lit différemment selon le document. Dans les métadonnées du serveur d’autorisation, il liste les méthodes acceptées par votre point de terminaison de jetons. Dans le document CIMD de ChatGPT, il liste celles que ChatGPT peut utiliser. ChatGPT sélectionne une méthode commune aux deux listes. Si la préférence indiquée dans l’ancien champ au singulier figure dans les deux listes, ChatGPT l’utilise pour rester compatible avec les serveurs d’autorisation qui considèrent encore ce champ comme contraignant. Dans le cas contraire, ChatGPT peut utiliser une autre méthode commune aux deux listes.

Les serveurs d’autorisation qui lisent le champ CIMD au pluriel devraient accepter toute méthode commune aux deux listes, sauf si leur politique de sécurité locale l’interdit pour le client concerné. Ils doivent rejeter toute autre méthode. L’URL client_id reste stable et n’utilise aucun paramètre de requête pour sélectionner un document propre à une méthode.

Les méthodes prises en charge sont les suivantes :

  • none : utilisez ce flux pour client public si votre point de terminaison de jetons accepte l’échange de codes d’autorisation avec PKCE sans authentifier le client. ChatGPT ne stocke pas de secret propre à chaque client.
  • private_key_jwt : utilisez ce flux avec assertion client signée si votre point de terminaison de jetons exige l’authentification du client. ChatGPT publie l’URL de son jeu de clés publiques JWKS dans ses métadonnées CIMD. Le JWKS est accessible au chemin /oauth/jwks.json sur la même origine que les métadonnées. ChatGPT signe les requêtes de jeton côté serveur avec une clé privée gérée et indique son kid. Votre serveur d’autorisation vérifie l’assertion à l’aide du JWKS public.

DCR reste pris en charge. Si vous incluez registration_endpoint, ChatGPT peut s’enregistrer dynamiquement lorsque le développeur du plugin choisit DCR ou que CIMD n’est pas disponible. ChatGPT procède à cet enregistrement une fois par connexion au serveur MCP, puis conserve et réutilise le client OAuth enregistré pour cette connexion. Avec de nombreuses connexions distinctes, DCR peut donc créer de nombreux clients enregistrés. CIMD est généralement plus simple à administrer à grande échelle.

Veillez à ce que le client OAuth enregistré et son éventuel secret restent valides tant que la connexion au serveur MCP est utilisée. Si votre serveur d’autorisation laisse expirer, supprime ou remplace l’un de ces éléments, les utilisateurs et les personnes chargées de l’évaluation risquent de recevoir une erreur invalid_client à la connexion. Les jetons d’accès et d’actualisation peuvent toujours expirer ou être renouvelés normalement.

Identification du client

Comment votre serveur MCP peut-il vérifier qu’une requête provient bien de ChatGPT ? ChatGPT présente un certificat client géré par OpenAI lorsqu’il se connecte aux serveurs MCP. Vous pouvez donc vérifier le client au niveau de la couche de transport avec mTLS. Vous pouvez également ajouter à votre liste d’autorisation les plages d’adresses IP sortantes publiées par ChatGPT. ChatGPT ne prend pas en charge les autorisations OAuth de machine à machine, telles que celles qui utilisent les identifiants client, les comptes de service ou les assertions JWT de type Bearer. Il ne peut pas non plus présenter de clés API personnalisées ni de certificats mTLS fournis par le client.

CIMD renforce l’identification du client en fournissant à votre serveur d’autorisation une déclaration stable de l’identité de ChatGPT, accessible via HTTPS. Si vous utilisez private_key_jwt, vérifiez l’assertion client présentée par ChatGPT au point de terminaison de jetons à l’aide du JWKS public indiqué dans les métadonnées CIMD.

TLS mutuel (mTLS)

ChatGPT présente désormais un certificat client géré par OpenAI lorsqu’il établit une connexion TLS à un serveur MCP. Si votre application valide les certificats clients, configurez-la pour qu’elle fasse confiance à la chaîne de certification OpenAI ci-dessous.

Pour valider le certificat client lors de l’établissement de la connexion TLS à votre serveur MCP :

  • Vérifiez qu’un certificat terminal est présent et que sa chaîne de certification remonte à l’autorité intermédiaire mTLS des connecteurs OpenAI.
  • Vérifiez que le certificat terminal est valide pour l’authentification du client.
  • Vérifiez que le champ dnsName du SAN du certificat terminal vaut mtls.prod.connectors.openai.com.
  • Évitez d’épingler l’empreinte du certificat terminal. OpenAI peut le renouveler tout en conservant la chaîne de certification publiée.

Utilisez mTLS pour authentifier ChatGPT en tant que client MCP. Continuez d’utiliser OAuth 2.1 pour authentifier l’utilisateur final et autoriser l’accès aux outils.

Choix d’un fournisseur d’identité

La plupart des fournisseurs d’identité OAuth 2.1 peuvent satisfaire aux exigences d’autorisation MCP s’ils exposent un document de découverte, prennent en charge CIMD avec none ou private_key_jwt ainsi que DCR si nécessaire, et reprennent la valeur du paramètre resource dans les jetons délivrés. Privilégiez les fournisseurs qui prennent en charge CIMD pour l’enregistrement des clients.

Nous vous recommandons vivement de choisir un fournisseur d’identité éprouvé plutôt que de développer vous-même tout le mécanisme d’authentification.

Voici les instructions de quelques fournisseurs d’identité courants.

Auth0

Auth0 permet aux clients MCP de se connecter en toute sécurité aux serveurs MCP. Il prend en charge la découverte des métadonnées, l’enregistrement via CIMD, la sécurisation des API et l’échange de jetons pour les appels à des outils internes ou tiers.

Exemple de fournisseur hébergé (Stytch)

Mise en œuvre de la vérification des jetons

À la fin du flux OAuth, ChatGPT joint directement le jeton d’accès reçu aux requêtes MCP suivantes (Authorization: Bearer …). Lorsqu’une requête arrive sur votre serveur MCP, traitez le jeton comme non fiable et effectuez vous-même tous les contrôles qui incombent au serveur de ressources. Validez la signature, vérifiez que l’émetteur et l’audience correspondent aux valeurs attendues, contrôlez l’expiration, tenez compte du risque de rejeu et faites respecter les portées. Ces vérifications relèvent de votre responsabilité, pas de celle de ChatGPT.

En pratique :

  • Récupérez les clés de signature publiées par votre serveur d’autorisation (généralement via JWKS) et vérifiez la signature du jeton ainsi que sa revendication iss.
  • Rejetez les jetons expirés ou qui ne sont pas encore valides (exp/nbf).
  • Vérifiez que le jeton a été délivré pour votre serveur (revendication aud ou resource) et qu’il contient les portées que vous exigez.
  • Appliquez les contrôles propres aux politiques de votre serveur, puis associez l’identité obtenue au contexte de la requête ou renvoyez une réponse 401 avec un défi WWW-Authenticate.

Si la vérification échoue, renvoyez 401 Unauthorized avec un en-tête WWW-Authenticate qui pointe vers les métadonnées de votre ressource protégée. Le client sait ainsi qu’il doit relancer le flux OAuth.

Fonctions de vérification des jetons dans les SDK

Les SDK MCP pour Python et TypeScript fournissent des fonctions qui vous évitent de mettre en œuvre toute cette logique vous-même.

Prenez en charge plusieurs comptes

Les utilisateurs peuvent connecter plusieurs comptes au même plugin, par exemple un compte personnel et un compte professionnel. OpenAI achemine chaque appel d’outil avec les informations d’authentification de la connexion sélectionnée. Les utilisateurs peuvent connecter plusieurs comptes même en l’absence d’un outil de profil. Pour les aider à distinguer les connexions et à reconnaître le même profil après une reconnexion, fournissez un outil de profil authentifié qui renvoie un identifiant stable et des métadonnées d’affichage utiles.

Utilisation de plusieurs comptes

Les utilisateurs peuvent connecter des comptes supplémentaires depuis la page des paramètres du plugin. Le modèle a accès à tous les comptes connectés. Lorsqu’il appelle des outils, il sélectionne le ou les comptes pertinents en fonction de la demande de l’utilisateur. Chaque appel utilise les informations d’authentification et les autorisations du compte sélectionné.

Améliorez l’identification des comptes

Pour aider OpenAI à reconnaître les profils connectés et à afficher des libellés utiles :

  • Fournissez un outil de profil authentifié qui renvoie un identifiant opaque, unique et stable pour le profil correspondant aux informations d’authentification de la requête. OpenAI peut ainsi reconnaître le même profil après une reconnexion et le distinguer des autres. Un champ nommé id ne convient à cet usage que si sa valeur offre ces garanties.
  • Indiquez l’outil de profil dans les métadonnées MCP pour qu’OpenAI puisse déterminer quel outil appeler afin d’obtenir les informations sur le profil authentifié.

Lorsqu’OpenAI a besoin d’informations sur un profil, il repère l’outil déclaré au moment de l’exécution, l’appelle avec les informations d’authentification de la connexion et valide la réponse avant d’utiliser les données du profil. Sans outil de profil, les utilisateurs peuvent toujours connecter des comptes, mais les libellés des comptes, leur reconnaissance ou la détection des doublons peuvent être moins fiables. Si vous déclarez un outil de profil, renvoyez une identité valide. Une réponse non valide peut empêcher la connexion du compte.

Définissez une identité stable pour chaque profil

Un profil correspond à l’identité établie à partir des informations d’authentification validées de la requête. Votre service détermine quels profils peuvent être connectés indépendamment. Ce contrat ne vous impose aucune structure d’organisation ni aucun modèle d’autorisation.

Renvoyez un identifiant de profil opaque et unique au sein de votre application. Un profil doit conserver son identifiant après l’actualisation du jeton ou une reconnexion. Des profils distincts doivent avoir des identifiants distincts. OpenAI compare ces identifiants sans en interpréter le contenu.

Utilisez un identifiant opaque et immuable déjà attribué par le fournisseur s’il identifie le profil dans son intégralité. Sinon, attribuez un identifiant opaque une seule fois, enregistrez durablement son association avec le profil et récupérez ce même identifiant lors des requêtes suivantes. Conservez les relations internes dans votre service. N’encodez ni nom, ni adresse e-mail, ni lien organisationnel dans l’identifiant renvoyé.

Votre champ id doit respecter les critères suivants :

  • Contenir une chaîne non vide comportant au moins un caractère autre qu’un espace blanc. Sérialisez les identifiants numériques du fournisseur sous forme de chaînes.
  • Conserver la même valeur pour un profil donné après l’actualisation du jeton, une reconnexion ou l’extension des portées.
  • Avoir une valeur différente pour chaque profil distinct pouvant se connecter via l’application.
  • Rester inchangé si l’adresse e-mail, le nom ou le libellé affiché du profil change.
  • Ne jamais être réattribué à un autre profil après la suppression du profil d’origine.

Ne générez pas de nouvel identifiant à chaque connexion, jeton, session ou appel d’outil. Réservez l’adresse e-mail et les noms modifiables aux métadonnées d’affichage. Une adresse e-mail susceptible de changer ou d’être réattribuée ne peut pas servir d’identifiant de profil stable. Avec Google OIDC, utilisez la revendication stable sub plutôt que celle de l’adresse e-mail. Google précise que l’adresse e-mail peut changer, tandis que sub reste inchangé et n’est jamais réattribué. Consultez la documentation de Google sur l’identité.

Conservez les identifiants de profil existants lorsque vous mettez à jour votre intégration. Un changement de nom d’affichage, un nouveau jeton ou une nouvelle connexion ne doivent pas créer une nouvelle identité de profil.

Implémentez et déclarez votre outil de profil

Exposez un outil authentifié en lecture seule qui accepte un objet d’arguments vide et renvoie le profil courant. Vous pouvez le nommer get_profile, whoami ou lui donner un autre nom. Ses métadonnées permettent de l’identifier comme outil de profil au moment de l’exécution. Pour qu’OpenAI puisse utiliser correctement sa réponse, celle-ci doit respecter les exigences d’identité ci-dessous.

  • Déterminez l’identité à partir des informations d’authentification validées de la requête.
  • Limitez l’opération à la lecture seule et rendez-la accessible avec les autorisations habituelles de la connexion.
  • Renvoyez exactement un profil, celui qui correspond aux informations d’authentification de la requête en cours.
  • N’exigez pas que l’appelant fournisse un identifiant utilisateur, une adresse e-mail ou un paramètre de sélection du compte.
  • En cas d’échec de l’authentification, renvoyez l’erreur d’authentification appropriée plutôt qu’un identifiant de substitution ou le profil d’un autre compte.

La réponse de l’outil de profil doit respecter le schéma JSON suivant :

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "minLength": 1,
      "pattern": "\\S",
      "description": "Opaque profile identifier, unique within this app and unchanged across token refresh, reconnection, and display-metadata changes. Never reassigned to another profile."
    },
    "name": {
      "type": "string",
      "description": "Display name for the authenticated profile."
    },
    "email": {
      "type": "string",
      "description": "Email address for display; not used as the profile identity."
    },
    "nickname": {
      "type": "string",
      "description": "A useful label that helps users distinguish connected profiles."
    }
  },
  "required": ["id"],
  "additionalProperties": false
}

La réponse doit contenir un champ id dont la valeur est une chaîne non vide comportant au moins un caractère autre qu’un espace blanc. Les champs d’affichage sont facultatifs. Les métadonnées de l’outil indiquent à OpenAI où récupérer les informations du profil. La réponse identifie le profil correspondant aux informations d’authentification utilisées pour la requête.

La validation du schéma vérifie que la réponse a la structure et les types de champs nécessaires au traitement du profil. Votre service doit également garantir que l’identifiant est unique, stable et qu’il correspond bien au profil associé aux informations d’authentification reçues. Ni les métadonnées ni la réussite de la validation du schéma ne garantissent ces propriétés.

Incluez les champs name, email et/ou nickname lorsqu’ils sont disponibles pour que les utilisateurs puissent distinguer les profils. Omettez les valeurs facultatives indisponibles. Ne les inventez pas et n’ajoutez pas de données personnelles sans rapport avec le profil. Placez les indications utiles et lisibles dans nickname plutôt que dans l’identifiant.

Marquez l’outil avec _meta["openai/profile"]: true et publiez le schéma de sa réponse dans outputSchema. Le marqueur indique à OpenAI quel outil fournit les informations de profil. Il n’active pas la fonctionnalité et ne rend pas l’application éligible. Si le marqueur est absent ou vaut faux, ce mécanisme ne désigne pas l’outil comme source d’informations de profil. Les chaînes, les nombres et la valeur nulle ne sont pas des valeurs valides pour ce marqueur.

{
  "name": "get_profile",
  "description": "Return the profile represented by this request's authenticated credentials. The opaque id is unique within this app and remains unchanged across token refresh, reconnection, and display-metadata changes.",
  "inputSchema": {
    "type": "object",
    "properties": {},
    "additionalProperties": false
  },
  "outputSchema": {
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "type": "object",
    "properties": {
      "id": {
        "type": "string",
        "minLength": 1,
        "pattern": "\\S",
        "description": "Opaque profile identifier, unique within this app and unchanged across token refresh, reconnection, and display-metadata changes. Never reassigned to another profile."
      },
      "name": {
        "type": "string",
        "description": "Display name for the authenticated profile."
      },
      "email": {
        "type": "string",
        "description": "Email address for display; not used as the profile identity."
      },
      "nickname": {
        "type": "string",
        "description": "A useful label that helps users distinguish connected profiles."
      }
    },
    "required": ["id"],
    "additionalProperties": false
  },
  "annotations": {
    "readOnlyHint": true,
    "destructiveHint": false,
    "openWorldHint": false
  },
  "securitySchemes": [
    {
      "type": "oauth2",
      "scopes": []
    }
  ],
  "_meta": {
    "openai/profile": true
  }
}

Si l’accès au profil exige des portées OAuth, indiquez celles que votre intégration utilise réellement. Cette déclaration n’assure pas l’authentification. Le serveur doit valider les informations d’authentification et faire respecter les autorisations. Consultez la section Mise en œuvre de la vérification des jetons et la documentation de référence des outils.

Renvoyez le profil dans structuredContent pour permettre sa validation par rapport à outputSchema. Par souci de compatibilité, incluez également le même profil sérialisé en JSON dans un élément de contenu textuel :

{
  "content": [
    {
      "type": "text",
      "text": "{\"id\":\"prf_8d7e4b19\",\"name\":\"Alex Chen\",\"email\":\"alex@example.com\",\"nickname\":\"Alex — Moonwaffle work\"}"
    }
  ],
  "structuredContent": {
    "id": "prf_8d7e4b19",
    "name": "Alex Chen",
    "email": "alex@example.com",
    "nickname": "Alex — Moonwaffle work"
  },
  "isError": false
}

Utilisez un seul objet JSON et placez les champs du profil à la racine.

Vous disposez déjà d’un outil de profil ? Conservez son nom, ajoutez la déclaration de métadonnées de profil et renvoyez la réponse de profil standard. Si la réponse existante a une structure différente, adaptez-la sur votre serveur ou exposez un petit outil qui appelle l’outil existant et renvoie une réponse conforme au schéma. L’intégration standard utilise la même déclaration et la même structure de réponse pour toutes les applications.

Exemple concret de profils persistants dans Moonwaffle

Supposons que Moonwaffle, un service fictif, permette à Alex de connecter deux profils indépendamment. Moonwaffle enregistre un identifiant opaque différent pour chaque profil. Les informations d’authentification de la requête permettent de retrouver l’un de ces profils, puis l’outil de profil renvoie son identifiant existant.

Exemples de profils enregistrés. Les libellés peuvent changer, mais les identifiants restent les mêmes :

Alex — Moonwaffle personal: prf_42a9c6e0
Alex — Moonwaffle work:     prf_8d7e4b19

Ces exemples d’identifiants n’encodent ni les libellés des profils ni leurs relations internes. Ils sont enregistrés une seule fois par profil, puis réutilisés après une reconnexion, une actualisation du jeton ou une modification de l’adresse e-mail ou du nom d’affichage.

Construisez la réponse à partir du profil authentifié. Cet exemple JavaScript illustre un gestionnaire que vous pouvez intégrer à votre SDK MCP. La fonction loadAuthenticatedProfile relève du code d’intégration de votre application. Elle valide les informations d’authentification de la requête, applique les autorisations associées et récupère l’identifiant enregistré ainsi que les métadonnées d’affichage du profil correspondant. Votre serveur fournit requestContext lors du traitement de la requête. Le modèle ne le transmet pas comme argument de l’outil.

async function getProfile(requestContext) {
  // Your auth/provider integration validates credentials and loads
  // the existing profile. Auth failures use normal MCP auth handling.
  const account = await loadAuthenticatedProfile(requestContext);
  const id = account.profileId;

  if (typeof id !== "string" || id.trim().length === 0) {
    return {
      isError: true,
      content: [{ type: "text", text: "Profile identity unavailable." }],
    };
  }

  // Return the persisted ID unchanged; do not generate an ID per call.
  const profile = {
    id,
    ...(typeof account.name === "string" ? { name: account.name } : {}),
    ...(typeof account.email === "string" ? { email: account.email } : {}),
    ...(typeof account.nickname === "string"
      ? { nickname: account.nickname }
      : {}),
  };

  return {
    isError: false,
    structuredContent: profile,
    content: [{ type: "text", text: JSON.stringify(profile) }],
  };
}

Enregistrez ce gestionnaire avec la déclaration de métadonnées et les schémas d’entrée et de sortie ci-dessus. La fonction loadAuthenticatedProfile doit retrouver le même profil enregistré pour des informations d’authentification équivalentes, y compris après une reconnexion. Elle ne doit pas créer de nouvel identifiant de profil à chaque autorisation OAuth ou à chaque session. Tous les autres outils doivent utiliser les informations d’authentification de la requête pour faire respecter les autorisations de ce même profil.

Vérifiez le comportement des identifiants de profil :

Test Résultat attendu
Appels répétés pour le profil professionnel Moonwaffle prf_8d7e4b19 à chaque appel
Même profil après actualisation du jeton, reconnexion ou extension des portées prf_8d7e4b19
Même profil après modification de l’adresse e-mail ou du libellé affiché prf_8d7e4b19, même si les libellés changent
Profil personnel Moonwaffle prf_42a9c6e0, distinct de l’identifiant du profil professionnel
Identifiant enregistré du profil absent, vide ou composé uniquement d’espaces blancs Une réponse d’erreur, sans identité inventée ni recours à un autre profil

Ces garanties d’identité doivent s’appliquer à tous les profils et rester valables lorsque votre intégration évolue. Préservez-les indépendamment des métadonnées d’affichage, du contenu des jetons et des événements du cycle de vie de la connexion.

Tests et déploiement

  • Tests locaux : commencez avec un tenant de développement qui délivre des jetons de courte durée pour pouvoir enchaîner rapidement les essais.
  • Tests internes : une fois l’authentification opérationnelle, limitez l’accès à des testeurs de confiance avant de généraliser le déploiement. Vous pouvez exiger la liaison d’un compte pour certains outils ou pour l’ensemble du serveur MCP.
  • Rotation : prévoyez la révocation et l’actualisation des jetons ainsi que les changements de portée. Si le jeton est absent ou obsolète, votre serveur devrait traiter la requête comme non authentifiée et renvoyer un message d’erreur explicite.
  • Débogage OAuth : utilisez les paramètres Auth de MCP Inspector pour parcourir les étapes du flux OAuth et repérer précisément celle qui échoue avant le déploiement.

Une fois l’authentification en place, vous pouvez donner aux utilisateurs de ChatGPT et de Codex accès à leurs propres données et à des opérations d’écriture.

Déclenchement de l’interface d’authentification

ChatGPT affiche son interface de liaison de compte OAuth uniquement lorsque votre serveur MCP signale qu’OAuth est disponible ou nécessaire.

Pour déclencher le flux OAuth d’un outil, vous devez fournir les métadonnées (securitySchemes et le document de métadonnées de la ressource) et renvoyer des erreurs d’exécution contenant _meta["mcp/www_authenticate"]. ChatGPT n’affichera l’interface de liaison de compte pour cet outil que si les deux conditions sont réunies.

  1. Publiez les métadonnées de la ressource. Le serveur MCP doit exposer sa configuration OAuth à une URL de découverte standard telle que https://your-mcp.example.com/.well-known/oauth-protected-resource.

  2. Décrivez la politique d’authentification de chaque outil avec securitySchemes. Déclarez securitySchemes pour chaque outil afin que ChatGPT sache lesquels exigent OAuth et lesquels peuvent être appelés anonymement. Conservez une déclaration par outil même si tout le serveur applique la même politique. Avec des valeurs par défaut définies au niveau du serveur, il sera plus difficile de faire évoluer chaque outil séparément.

    Deux types de mécanismes sont actuellement disponibles. Vous pouvez en déclarer plusieurs pour indiquer que l’authentification est facultative :

    • noauth : l’outil accepte les appels anonymes. ChatGPT peut l’exécuter immédiatement.
    • oauth2 : l’outil exige un jeton d’accès OAuth 2.0. Indiquez les portées que vous demanderez afin que l’écran de consentement les présente correctement.

    Si vous omettez entièrement le tableau, l’outil hérite du mécanisme par défaut déclaré par le serveur. En déclarant à la fois noauth et oauth2, vous indiquez à ChatGPT qu’il peut commencer par des appels anonymes et que la liaison d’un compte donne accès aux opérations nécessitant des privilèges. Quelles que soient les indications transmises au client, votre serveur doit vérifier le jeton, les portées et l’audience à chaque appel.

    Exemple avec le SDK TypeScript (accès public et authentification facultative)

    import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
    import { z } from "zod";
    
    const server = new McpServer({ name: "auth-example", version: "1.0.0" });
    
    server.registerTool(
      "search",
      {
        title: "Public Search",
        description: "Search public documents.",
        inputSchema: {
          q: z.string(),
        },
        outputSchema: {},
        _meta: {
          securitySchemes: [
            { type: "noauth" },
            { type: "oauth2", scopes: ["search.read"] },
          ],
        },
      },
      async ({ q }) => {
        return {
          content: [{ type: "text", text: `Results for ${q}` }],
          structuredContent: {},
        };
      }
    );

    Exemple avec le SDK TypeScript (authentification obligatoire)

    import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
    import { z } from "zod";
    
    const server = new McpServer({ name: "auth-example", version: "1.0.0" });
    
    server.registerTool(
      "create_doc",
      {
        title: "Create Document",
        description: "Make a new doc in your account.",
        inputSchema: {
          title: z.string(),
        },
        outputSchema: {},
        _meta: {
          securitySchemes: [{ type: "oauth2", scopes: ["docs.write"] }],
        },
      },
      async ({ title }) => {
        return {
          content: [{ type: "text", text: `Created doc: ${title}` }],
          structuredContent: {},
        };
      }
    );
  3. Vérifiez les jetons dans le gestionnaire de l’outil et renvoyez _meta["mcp/www_authenticate"] lorsque vous souhaitez que ChatGPT affiche l’interface d’authentification. Examinez le jeton et vérifiez son émetteur, son audience, son expiration et ses portées. En l’absence de jeton valide, renvoyez une réponse d’erreur contenant _meta["mcp/www_authenticate"] et assurez-vous que sa valeur contient les deux paramètres error et error_description. Une fois les étapes 1 et 2 en place, c’est le contenu de WWW-Authenticate qui déclenche l’affichage de l’interface OAuth pour cet outil. Lorsqu’un défi d’authentification demande une nouvelle autorisation, votre fournisseur peut conserver le contexte de connexion de l’utilisateur pendant ce flux.

    Exemple

    {
      "jsonrpc": "2.0",
      "id": 4,
      "result": {
        "content": [
          {
            "type": "text",
            "text": "Authentication required: no access token provided."
          }
        ],
        "_meta": {
          "mcp/www_authenticate": [
            "'Bearer resource_metadata=\"https://your-mcp.example.com/.well-known/oauth-protected-resource\", error=\"insufficient_scope\", error_description=\"You need to login to continue\"'"
          ]
        },
        "isError": true
      }
    }