对您的用户进行身份验证
许多 Apps SDK 应用可以在只读的匿名模式下运行,但任何暴露客户特定数据或涉及写入操作的应用都应验证用户身份。
当您需要连接到现有后端或在用户之间共享数据时,可以与您自己的授权服务器进行集成。
使用 OAuth 2.1 进行自定义身份验证
对于经过身份验证的 MCP 服务器,您需要实现符合 MCP 授权规范 的 OAuth 2.1 流程。
组件
- 资源服务器 – 您的 MCP 服务器,负责公开工具并在每个请求上验证访问令牌。
- 授权服务器 – 您的身份提供商(Auth0、Okta、Cognito 或自定义实现),负责颁发令牌并发布发现元数据。
- 客户端 – 代表用户行事的 ChatGPT。它支持客户端 ID 元数据文档 (CIMD)、动态客户端注册 (DCR)、预定义 OAuth 客户端和 PKCE。
MCP 授权规范要求
- 在您的 MCP 服务器上托管受保护的资源元数据
- 从您的授权服务器发布 OAuth 元数据
- 在整个 OAuth 流程中回传
resource参数 - 选择 ChatGPT 识别或注册其 OAuth 客户端的方式:CIMD、DCR 或预定义 OAuth 客户端
- 发布您的授权服务器接受的令牌端点身份验证方法
以下是该规范的通俗解释。
在您的 MCP 服务器上托管受保护的资源元数据
- 您需要一个 HTTPS 端点(例如
GET https://your-mcp.example.com/.well-known/oauth-protected-resource,或者在401 Unauthorized响应的WWW-Authenticate标头中通告同一 URL),以便 ChatGPT 知道在哪里获取您的元数据。 - 该端点返回一个 JSON 文档,描述资源服务器及其可用的授权服务器。
{
"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"
}
- 您必须填充的关键字段
resource:您的 MCP 服务器的规范 HTTPS 标识符。在 OAuth 过程中,ChatGPT 会将此确切值作为resource查询参数发送。authorization_servers:一个或多个指向您身份提供商的颁发者基本 URL。ChatGPT 将尝试每一个以查找 OAuth 元数据。scopes_supported:可选列表,有助于 ChatGPT 向用户说明它将请求哪些权限。- 来自 RFC 9728 的可选扩展(如
resource_documentation、token_endpoint_auth_methods_supported或introspection_endpoint)使客户端和管理员更容易理解您的设置。
当您因未通过身份验证而拦截请求时,请返回如下质询:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://your-mcp.example.com/.well-known/oauth-protected-resource",
scope="files:read"
这一个标头即使在 ChatGPT 之前未见过该 URL 的情况下,也能让其发现元数据 URL。
从您的授权服务器发布 OAuth 元数据
- 您的身份提供商必须公开其中一个众所周知的发现文档,以便 ChatGPT 可以读取其配置。
- 位于
https://auth.yourcompany.com/.well-known/oauth-authorization-server的 OAuth 2.0 元数据 - 位于
https://auth.yourcompany.com/.well-known/openid-configuration的 OpenID Connect 元数据
- 位于
- 每个文档都为 ChatGPT 回答了三个重要问题:将用户发送到哪里、如何交换代码以及如何识别自身。一个典型的响应如下:
{
"issuer": "https://auth.yourcompany.com",
"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"]
}
- 必须正确的字段
authorization_endpoint,token_endpoint:ChatGPT 运行 OAuth 授权码 + PKCE 流程所需的 URL。client_id_metadata_document_supported:当您希望 ChatGPT 使用 CIMD 进行客户端注册时,将其设置为true。当 CIMD 可用时,ChatGPT 会优先使用 CIMD,但连接器创建者可以在 CIMD 和 DCR 同时可用时选择 DCR。token_endpoint_auth_methods_supported:包含您的授权服务器接受的令牌端点身份验证方法。这适用于 CIMD、DCR 和预定义的 OAuth 客户端。对于 CIMD,ChatGPT 支持none(用于公共客户端令牌交换)和private_key_jwt(用于签名的客户端断言令牌交换)。其他 OAuth 客户端通常使用none、client_secret_post或client_secret_basic。registration_endpoint:当您支持动态客户端注册 (DCR) 时包含此项,它允许 ChatGPT 为该连接器实例创建并重用专用的client_id。code_challenge_methods_supported:如果您的授权服务器通告支持 PKCE,请包含S256。- 可选字段遵循 RFC 8414 / OpenID Discovery;请包含任何有助于您的管理员配置策略的信息。
OIDC 作用域
- 如果您的提供商在其
.well-known/oauth-authorization-server或.well-known/openid-configuration文档的scopes_supported中通告了 OIDC 作用域(例如openid、email、profile),ChatGPT 将在 OAuth 流程中默认请求这些作用域。 - 某些身份提供商可能不会默认启用已通告的 OIDC 作用域。请检查您提供商的配置设置,并确保无论使用的是 CIMD、手动创建还是通过 DCR 创建,每个已通告的作用域都已为该 OAuth 客户端启用。
重定向 URL
ChatGPT 通过重定向到 https://chatgpt.com/connector/oauth/{callback_id} 来完成 OAuth 流程,该 URL 将显示在应用管理页面中。请将该生产环境重定向 URI 添加到您授权服务器的允许列表中,以便成功返回授权码。
- 对于已经发布的应用,旧版的重定向 URI
https://chatgpt.com/connector_platform_oauth_redirect将继续有效。
在整个 OAuth 流程中回传 resource 参数
- 预计 ChatGPT 会在授权请求和令牌请求中附加
resource=https%3A%2F%2Fyour-mcp.example.com。这会将令牌与上面显示的受保护资源元数据关联起来。 - 配置您的授权服务器,将该值复制到访问令牌中(通常是
aud声明),以便您的 MCP 服务器可以验证该令牌是为它颁发的,而不是其他任何服务。 - 如果收到的令牌缺少预期的受众或作用域,请拒绝它,并依靠
WWW-Authenticate质询来提示 ChatGPT 使用正确的参数重新进行授权。
支持授权码流程
- 作为 MCP 客户端,ChatGPT 使用
S256代码质询执行带有 PKCE 的授权码流程,从而防止拦截的授权码被攻击者重用。 - 如果您的授权服务器发布了
code_challenge_methods_supported,请包含S256,以便客户端可以通过元数据确认对 PKCE 的支持。
OAuth 流程
只要您按照上述说明实现了 MCP 授权规范,OAuth 流程将如下进行:
- ChatGPT 向您的 MCP 服务器查询受保护的资源元数据。

- ChatGPT 将自己标识为 OAuth 客户端。当连接器使用 CIMD 时,ChatGPT 会跳过动态客户端注册,并发送一个 CIMD 文档 URL 作为
client_id,例如https://chatgpt.com/oauth/.../client.json(确切的 URL 特定于 MCP 服务器,因为重定向 URI 是 MCP 特有的)。当连接器使用 DCR 时,ChatGPT 会为该连接器实例调用一次授权服务器的registration_endpoint,接收生成的client_id,并为该实例重用此客户端。
使用 CIMD 时,没有客户端注册步骤。以下屏幕显示的是 DCR 路径:

- 当用户首次调用工具时,ChatGPT 客户端启动 OAuth 授权码 + PKCE 流程。用户进行身份验证并同意所请求的作用域。

- ChatGPT 将授权码交换为访问令牌,并将其附加到后续的 MCP 请求中(
Authorization: Bearer <token>)。

- 您的服务器在执行工具之前验证每个请求上的令牌(颁发者、受众、过期时间、作用域)。
客户端注册
当您的授权服务器支持且连接器创建者选择时,请将 客户端 ID 元数据文档 (CIMD) 作为首选客户端注册方法。使用 CIMD,ChatGPT 使用 HTTPS 元数据文档 URL 作为其 client_id。您的授权服务器获取该文档,验证已发布的客户端元数据和重定向 URI,并将该 URL 视为 ChatGPT 稳定的客户端身份。
如果您支持 CIMD,请在授权服务器元数据中设置 client_id_metadata_document_supported: true。这允许 ChatGPT 为选择 CIMD 的连接器使用一个稳定的客户端身份,您的授权服务器可以将其用于重定向 URI 允许列表、速率限制和其他策略。
ChatGPT 为 CIMD 支持的客户端支持两种令牌端点身份验证方法:
none:当您的令牌端点支持基于 PKCE 的授权码交换而无需客户端身份验证时,使用此公共客户端流程。ChatGPT 不会存储每个客户端的密钥。private_key_jwt:当您的令牌端点需要客户端身份验证时,使用此签名的客户端断言流程。ChatGPT 发布带有token_endpoint_auth_method: "private_key_jwt"和公共 JWKS URL 的 CIMD 元数据。JWKS 从元数据源的/oauth/jwks.json提供。ChatGPT 在服务器端使用托管的私钥和kid对令牌请求进行签名;您的授权服务器对照公共 JWKS 验证断言。
仍然支持 DCR。如果您包含 registration_endpoint,当连接器创建者选择 DCR 或 CIMD 不可用时,ChatGPT 可以进行动态注册。ChatGPT 为每个连接器实例运行一次 DCR,然后为该实例保留并重用注册的 OAuth 客户端。DCR 仍然可以在许多单独的连接器实例中创建许多注册的客户端,因此 CIMD 在大规模管理时通常更容易。
客户端识别
一个常见的问题是您的 MCP 服务器如何确认请求确实来自 ChatGPT。ChatGPT 在连接到 MCP 服务器时会出示由 OpenAI 托管的客户端证书,因此您可以在传输层使用 mTLS 验证客户端。您也可以将 ChatGPT 的 已发布的出站 IP 范围 加入白名单。ChatGPT 不支持机器对机器的 OAuth 授权,如客户端凭据、服务帐户或 JWT 承载断言,也无法出示自定义 API 密钥或客户提供的 mTLS 证书。
CIMD 通过为您的授权服务器提供一个稳定的、由 HTTPS 托管的 ChatGPT 身份声明,进一步加强了客户端识别。当您使用 private_key_jwt 时,请对照 CIMD 元数据中发布的公共 JWKS 验证 ChatGPT 的令牌端点客户端断言。
双向 TLS (mTLS)
当建立与 MCP 服务器的 TLS 连接时,ChatGPT 现在会出示由 OpenAI 托管的客户端证书。如果您的应用程序验证客户端证书,请将其配置为信任下面的 OpenAI 证书链。
要在建立与您的 MCP 服务器的 TLS 连接时验证客户端证书:
- 验证存在叶证书,并且它链接到 OpenAI 连接器 mTLS 中间 CA。
- 验证叶证书对客户端身份验证有效。
- 验证叶证书的 SAN
dnsName为mtls.prod.connectors.openai.com。 - 避免固定叶证书指纹;OpenAI 可能会轮换叶证书,同时保持其在已发布的 CA 链下。
使用 mTLS 验证 ChatGPT 作为 MCP 客户端。继续使用 OAuth 2.1 对最终用户进行身份验证并授权工具访问。
选择身份提供商
大多数 OAuth 2.1 身份提供商在公开发现文档、支持 none 或 private_key_jwt 的 CIMD、在需要时支持 DCR 以及将 resource 参数回传到颁发的令牌中后,都可以满足 MCP 授权要求。请优先选择支持 CIMD 的客户端注册的提供商。
我们强烈建议您使用现有的成熟身份提供商,而不是从头开始实现身份验证。
以下是一些常用身份提供商的操作说明。
Auth0
Auth0 通过提供元数据发现、CIMD 注册、API 安全性和针对第一方和第三方工具调用的令牌交换,使 MCP 客户端能够安全地连接到 MCP 服务器。
Stytch
实现令牌验证
当 OAuth 流程完成时,ChatGPT 只是将其收到的访问令牌附加到随后的 MCP 请求中(Authorization: Bearer …)。一旦请求到达您的 MCP 服务器,您必须假设令牌不可信,并亲自执行全套资源服务器检查——签名验证、颁发者和受众匹配、过期时间、重放考虑和作用域执行。此责任由您承担,而非 ChatGPT。
在实践中,您应该:
- 获取您的授权服务器发布的签名密钥(通常通过 JWKS),并验证令牌的签名和
iss。 - 拒绝已过期或尚未生效的令牌(
exp/nbf)。 - 确认令牌是为您服务器颁发的(
aud或resource声明),并包含您标记为必需的作用域。 - 运行任何特定于应用的策略检查,然后将解析后的身份附加到请求上下文,或者返回带有
WWW-Authenticate质询的401错误。
如果验证失败,请返回 401 Unauthorized 和指向您的受保护资源元数据的 WWW-Authenticate 标头。这会告诉客户端再次运行 OAuth 流程。
SDK 令牌验证原语
Python 和 TypeScript 的 MCP SDK 都包含辅助程序,因此您不必从头开始编写。
测试和发布
- 本地测试 – 从一个颁发短期令牌的开发租户开始,以便快速迭代。
- 内部测试 (Dogfood) – 一旦身份验证工作正常,在广泛发布之前限制受信任测试人员的访问。您可以要求针对特定工具或整个连接器进行链接。
- 轮换 – 规划令牌吊销、刷新和作用域更改。您的服务器应将丢失或陈旧的令牌视为未通过身份验证,并返回有用的错误消息。
- OAuth 调试 – 使用 MCP Inspector Auth 设置来逐步调试每个 OAuth 步骤,并在发布前查明流程中断的位置。
在完成身份验证后,您可以放心地向 ChatGPT 用户公开用户特定的数据和写入操作。
触发身份验证 UI
ChatGPT 仅在您的 MCP 服务器发出 OAuth 可用或必要的信号时,才会弹出其 OAuth 链接 UI。
触发工具级 OAuth 流程需要元数据(securitySchemes 和资源元数据文档)以及携带 _meta["mcp/www_authenticate"] 的运行时错误。缺一不可,ChatGPT 将不会为该工具显示链接 UI。
-
发布资源元数据。 MCP 服务器必须在众所周知的 URL(如
https://your-mcp.example.com/.well-known/oauth-protected-resource)上公开其 OAuth 配置。 -
使用
securitySchemes描述每个工具的身份验证策略。 为每个工具声明securitySchemes可以告诉 ChatGPT 哪些工具需要 OAuth,哪些可以匿名运行。即使整个服务器使用相同的策略,也要坚持使用工具级声明;服务器级默认值使得将来难以单独演进各个工具。目前有两种方案类型可用,您可以列出多个以表示可选的身份验证:
noauth— 工具可以匿名调用;ChatGPT 可以立即运行它。oauth2— 工具需要 OAuth 2.0 访问令牌;包含您将请求的作用域,以便同意屏幕准确无误。
如果您完全省略了该数组,则工具会继承服务器通告的任何默认值。同时声明
noauth和oauth2会告诉 ChatGPT,它可以从匿名调用开始,但链接操作可以解锁特权行为。无论您向客户端发出什么信号,您的服务器在每次调用时仍必须验证令牌、作用域和受众。示例(公开 + 可选身份验证)– TypeScript SDK
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; declare const server: McpServer; server.registerTool( "search", { title: "Public Search", description: "Search public documents.", inputSchema: { q: z.string(), }, outputSchema: {}, securitySchemes: [ { type: "noauth" }, { type: "oauth2", scopes: ["search.read"] }, ], }, async ({ q }) => { return { content: [{ type: "text", text: `Results for ${q}` }], structuredContent: {}, }; } );示例(需要身份验证)– TypeScript SDK
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; declare const server: McpServer; server.registerTool( "create_doc", { title: "Create Document", description: "Make a new doc in your account.", inputSchema: { title: z.string(), }, outputSchema: {}, securitySchemes: [{ type: "oauth2", scopes: ["docs.write"] }], }, async ({ title }) => { return { content: [{ type: "text", text: `Created doc: ${title}` }], structuredContent: {}, }; } ); -
在工具处理程序内部检查令牌并发出
_meta["mcp/www_authenticate"],当您希望 ChatGPT 触发身份验证 UI 时。检查令牌并验证颁发者、受众、过期时间和作用域。如果没有有效的令牌,请返回一个包含_meta["mcp/www_authenticate"]的错误结果,并确保该值包含error和error_description参数。一旦步骤 1 和 2 到位,这个WWW-Authenticate载荷就会实际触发工具级 OAuth UI。示例
{ "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 } }