メインコンテンツにスキップ

MCP サーバーで Bearer 認証を設定する

最新の MCP 仕様では、MCP サーバーは保護されたリソースのための リソースサーバー (Resource Server) として動作し、アクセス トークンの検証を行います。MCP Auth では、Bearer 認可 (Authorization) を設定するためのさまざまな方法が提供されています:

  • JWT (JSON Web Token) モード:クレーム (Claim) アサーションによって JWT を検証する組み込みの認可 (Authorization) 方法。
  • カスタムモード:独自の認可 (Authorization) ロジックを実装できます。

Bearer 認証 (Authentication) ミドルウェアでは、エンドポイントがどのリソースに属しているかを指定する必要があり、設定された認可 (Authorization) サーバーに対して適切なトークン検証が可能になります。

JWT モードで Bearer 認証 (Authentication) を設定する

OAuth / OIDC プロバイダーが認可 (Authorization) のために JWT を発行する場合、MCP Auth の組み込み JWT モードを利用できます。JWT の署名、有効期限、指定した他のクレーム (Claims) を検証し、その後、MCP 実装でさらに処理できるようにリクエストコンテキストに認証 (Authentication) 情報を格納します。

スコープ (Scope) とオーディエンス (Audience) の検証

オーディエンス (Audience) の検証

audience パラメーターは、OAuth 2.0 仕様で安全なトークン検証のために 必須 です。ただし、リソースインジケーターをまだサポートしていない認可 (Authorization) サーバーとの互換性を維持するため、現在は オプション となっています。セキュリティ上の理由から、可能な限り audience パラメーターを必ず含めてください。今後のバージョンでは、仕様に完全準拠するため audience 検証が必須となります。

常にスコープ (Scope) を検証する

OAuth 2.0 では、スコープ (Scope) は権限 (Permission) 管理の主要なメカニズムです。正しい audience を持つ有効なトークンがあっても、ユーザーがアクションを実行する権限 (Permission) を持っているとは限りません — 認可 (Authorization) サーバーは、空または制限されたスコープ (Scope) でトークンを発行する場合があります。

各操作に必要な権限 (Permission) がトークンに含まれていることを強制するために、常に requiredScopes を使用してください。有効なトークンが完全なアクセス権を意味すると決して仮定しないでください。

基本的なスコープ (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', // セキュリティのためオーディエンス検証を有効化
  requiredScopes: ['read', 'write'],
});

app.use('/mcp', bearerAuth, (req, res) => {
  // `req.auth` に認証 (Authentication) 情報が格納されます
  console.log(req.auth);
});

上記の例では:

  • audience パラメーターは、JWT の aud クレーム (Claim) を検証し、トークンが特定の MCP サーバーリソースのために発行されたことを確認します。audience の値は通常、リソースインジケーターと一致させます。
  • requiredScopes パラメーターは、JWT に read および write スコープ (Scope) が必要であることを指定します。トークンにこれらすべてのスコープ (Scope) が含まれていない場合、エラーが発生します。

JWT 検証にカスタムオプションを指定する

基盤となる JWT 検証ライブラリにカスタムオプションを指定することもできます。Node.js SDK では、JWT 検証に jose ライブラリを使用しています。指定できるオプションは以下の通りです:

  • 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 認証 (Authentication) の設定

OAuth / OIDC プロバイダーが JWT を発行しない場合や、独自の認可 (Authorization) ロジックを実装したい場合、MCP Auth ではカスタム検証関数を作成できます:

情報

Bearer 認証 (Authentication) ミドルウェアは、発行者 (iss)、オーディエンス (aud)、および必要なスコープ (scope) を検証結果と照合するため、これらのチェックをカスタム検証関数で実装する必要はありません。トークンの有効性(署名、有効期限など)の検証と、認証 (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', // セキュリティのためオーディエンス検証を有効化
    requiredScopes: ['read', 'write']
  }
);

MCP サーバーで Bearer 認証 (Authentication) を適用する

MCP サーバーを Bearer 認証 (Authentication) で保護するには、MCP サーバーインスタンスに Bearer 認証 (Authentication) ミドルウェアを適用します。

const app = express();
app.use(mcpAuth.bearerAuth('jwt', {
  resource: 'https://api.example.com',
  audience: 'https://api.example.com', // セキュリティのためオーディエンス検証を有効化
  requiredScopes: ['read', 'write']
}));

これにより、すべての受信リクエストが設定された Bearer 認証 (Authentication) 設定に従って認証 (Authentication) および認可 (Authorization) され、認証 (Authentication) 情報がリクエストコンテキストで利用可能になります。

MCP サーバー実装内で情報にアクセスできます:

// `authInfo` は `req.auth` オブジェクトから渡されます
server.registerTool(
  'whoami',
  {
    description: '現在のユーザー情報を返します',
    inputSchema: {},
  },
  ({ authInfo }) => {
    console.log(`認証 (Authentication) 済みユーザー: ${authInfo.subject}`);
    return { subject: authInfo.subject };
  }
);