跳转到主要内容

在 MCP 服务器中配置 Bearer 认证 (auth)

根据最新的 MCP 规范,你的 MCP 服务器充当资源服务器,用于验证受保护资源的访问令牌 (Access tokens)。MCP Auth 提供了多种方式来配置 Bearer 授权 (Authorization):

  • JWT (JSON Web Token) 模式:内置的授权 (Authorization) 方法,通过声明 (Claims) 断言验证 JWT。
  • 自定义模式:允许你实现自己的授权 (Authorization) 逻辑。

Bearer 认证 (auth) 中间件现在需要指定端点属于哪个资源,以便针对配置的授权 (Authorization) 服务器进行正确的令牌 (Token) 验证。

使用 JWT 模式配置 Bearer 认证 (auth)

如果你的 OAuth / OIDC 提供方为授权 (Authorization) 签发 JWT,你可以在 MCP Auth 中使用内置的 JWT 模式。它会验证 JWT 的签名、过期时间以及你指定的其他声明 (Claims);然后会将认证 (Authentication) 信息填充到请求上下文中,供你的 MCP 实现进一步处理。

权限 (Scope) 和受众 (Audience) 验证

受众 (Audience) 验证

根据 OAuth 2.0 规范,audience 参数是必需的,用于安全的令牌 (Token) 验证。但目前为了兼容尚未支持资源指示器 (Resource indicators) 的授权 (Authorization) 服务器,该参数为可选。出于安全考虑,请尽可能始终包含 audience 参数。未来版本将强制要求受众 (Audience) 验证,以完全符合规范。

始终校验权限 (Scopes)

在 OAuth 2.0 中,权限 (Scopes) 是权限控制的主要机制。一个具有正确 audience 的有效令牌并不保证用户有执行某个操作的权限 —— 授权 (Authorization) 服务器可能会签发带有空或受限权限 (Scope) 的令牌。

始终使用 requiredScopes 来强制令牌包含每个操作所需的权限 (Permissions)。切勿假设一个有效令牌就意味着完全访问权限。

以下是基本权限 (Scope) 和受众 (Audience) 验证的示例:

import express from 'express';
import { MCPAuth } from 'mcp-auth';

const app = express();
const mcpAuth = new MCPAuth({
  /* ... */
});
const bearerAuth = mcpAuth.bearerAuth('jwt', {
  resource: 'https://api.example.com', // 指定该端点属于哪个资源
  audience: 'https://api.example.com', // 启用受众 (Audience) 验证以增强安全性
  requiredScopes: ['read', 'write'],
});

app.use('/mcp', bearerAuth, (req, res) => {
  // 现在 `req.auth` 包含认证 (Authentication) 信息
  console.log(req.auth);
});

在上面的示例中:

  • audience 参数会验证 JWT 中的 aud 声明 (Claim),以确保令牌 (Token) 是专门为你的 MCP 服务器资源签发的。受众 (Audience) 的值通常应与你的资源标识符一致。
  • requiredScopes 参数指定 JWT 需要包含 readwrite 权限 (Scopes)。如果令牌 (Token) 未包含所有这些权限 (Scopes),将会抛出错误。

为 JWT 验证提供自定义选项

你还可以为底层的 JWT 验证库提供自定义选项。在 Node.js SDK 中,我们使用 jose 库进行 JWT 验证。你可以提供以下选项:

  • jwtVerify:JWT 验证过程的选项(josejwtVerify 函数)。
  • remoteJwtSet:用于获取远程 JWT 集的选项(josecreateRemoteJWKSet 函数)。
const bearerAuth = mcpAuth.bearerAuth('jwt', {
  resource: 'https://api.example.com',
  audience: 'https://api.example.com',
  requiredScopes: ['read', 'write'],
  jwtVerify: {
    clockTolerance: 60, // 允许 60 秒的时钟偏差
  },
  remoteJwtSet: {
    timeoutDuration: 10 * 1000, // 获取远程 JWT 集的超时时间为 10 秒
  },
});

使用自定义验证配置 Bearer 认证 (auth)

如果你的 OAuth / OIDC 提供方不签发 JWT,或者你希望实现自己的授权 (Authorization) 逻辑,MCP Auth 允许你创建自定义验证函数:

信息

由于 Bearer 认证 (auth) 中间件会根据发行者 (Issuer)(iss)、受众 (Audience)(aud)和所需权限 (Scopes)(scope)对给定的验证结果进行检查,因此你无需在自定义验证函数中实现这些检查。你只需专注于验证令牌 (Token) 的有效性(如签名、过期等)并返回认证 (Authentication) 信息对象即可。

const bearerAuth = mcpAuth.bearerAuth(
  async (token) => {
    // 在这里实现你的自定义验证逻辑
    const info = await verifyToken(token);
    if (!info) {
      throw new MCPAuthJwtVerificationError('jwt_verification_failed');
    }
    return info; // 返回认证 (Authentication) 信息对象
  },
  {
    resource: 'https://api.example.com',
    audience: 'https://api.example.com', // 启用受众 (Audience) 验证以增强安全性
    requiredScopes: ['read', 'write']
  }
);

在你的 MCP 服务器中应用 Bearer 认证 (auth)

要使用 Bearer 认证 (auth) 保护你的 MCP 服务器,你需要将 Bearer 认证 (auth) 中间件应用到 MCP 服务器实例上。

const app = express();
app.use(mcpAuth.bearerAuth('jwt', {
  resource: 'https://api.example.com',
  audience: 'https://api.example.com', // 启用受众 (Audience) 验证以增强安全性
  requiredScopes: ['read', 'write']
}));

这将确保所有传入请求都根据配置的 Bearer 认证 (auth) 设置进行认证 (Authentication) 和授权 (Authorization),并且认证 (Authentication) 信息会在请求上下文中可用。

你随后可以在 MCP 服务器实现中访问这些信息:

// `authInfo` 会从 `req.auth` 对象中传递过来
server.registerTool(
  'whoami',
  {
    description: '返回当前用户信息',
    inputSchema: {},
  },
  ({ authInfo }) => {
    console.log(`认证 (Authentication) 用户: ${authInfo.subject}`);
    return { subject: authInfo.subject };
  }
);