메인 콘텐츠로 건너뛰기

MCP 서버에서 Bearer 인증(Bearer auth) 구성하기

최신 MCP 명세에 따라, MCP 서버는 보호된 리소스에 대한 액세스 토큰을 검증하는 리소스 서버 (Resource Server) 역할을 합니다. MCP Auth는 Bearer 인가 (Authorization)를 구성하는 다양한 방법을 제공합니다:

  • JWT (JSON Web Token) 모드: 클레임 어설션으로 JWT를 검증하는 내장 인가 방식입니다.
  • 커스텀 모드: 직접 인가 로직을 구현할 수 있습니다.

Bearer 인증 미들웨어는 이제 엔드포인트가 속한 리소스를 지정해야 하며, 이를 통해 구성된 인가 서버에 대해 적절한 토큰 검증이 가능합니다.

JWT 모드로 Bearer 인증 구성하기

OAuth / OIDC 제공자가 인가를 위해 JWT를 발급하는 경우, MCP Auth의 내장 JWT 모드를 사용할 수 있습니다. 이 모드는 JWT 서명, 만료, 그리고 지정한 기타 클레임을 검증합니다. 이후 인증 (Authentication) 정보를 요청 컨텍스트에 채워 MCP 구현에서 추가 처리를 할 수 있게 합니다.

스코프(Scope) 및 대상(Audience) 검증

대상(Audience) 검증

audience 파라미터는 안전한 토큰 검증을 위해 OAuth 2.0 명세에서 필수입니다. 하지만, 아직 리소스 식별자를 지원하지 않는 인가 서버와의 호환성을 위해 현재는 선택 사항입니다. 보안상의 이유로, 가능한 경우 항상 audience 파라미터를 포함하세요. 향후 버전에서는 명세 준수를 위해 audience 검증이 필수로 적용될 예정입니다.

항상 스코프(Scopes)를 검증하세요

OAuth 2.0에서 스코프(Scopes)는 권한(권한) 제어의 주요 메커니즘입니다. 올바른 audience를 가진 유효한 토큰이 있다고 해서 사용자가 어떤 작업을 수행할 권한이 있다는 것을 보장하지 않습니다 — 인가 (Authorization) 서버는 빈 스코프 또는 제한된 스코프를 가진 토큰을 발급할 수 있습니다.

항상 requiredScopes를 사용하여 각 작업에 필요한 권한(권한)이 토큰에 포함되어 있는지 강제하세요. 유효한 토큰이 곧 전체 접근 권한을 의미한다고 절대 가정하지 마세요.

아래는 기본적인 스코프 및 대상 검증 예시입니다:

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`에 인증 정보가 포함됨
  console.log(req.auth);
});

위 예시에서:

  • audience 파라미터는 JWT의 aud 클레임을 검증하여, 토큰이 MCP 서버 리소스를 위해 발급되었는지 확인합니다. audience 값은 일반적으로 리소스 식별자와 일치해야 합니다.
  • requiredScopes 파라미터는 JWT에 readwrite 스코프가 모두 포함되어야 함을 명시합니다. 토큰에 이 스코프들이 모두 없으면 오류가 발생합니다.

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 인증 구성하기

OAuth / OIDC 제공자가 JWT를 발급하지 않거나, 직접 인가 로직을 구현하고 싶은 경우, MCP Auth는 커스텀 검증 함수를 만들 수 있도록 지원합니다:

정보

Bearer 인증 미들웨어는 발급자 (iss), 대상 (aud), 필수 스코프 (scope)를 검증 결과와 함께 확인하므로, 커스텀 검증 함수에서 이 검증들을 직접 구현할 필요가 없습니다. 토큰의 유효성(예: 서명, 만료 등) 검증과 인증 정보 객체 반환에 집중하면 됩니다.

const bearerAuth = mcpAuth.bearerAuth(
  async (token) => {
    // 여기서 커스텀 검증 로직을 구현
    const info = await verifyToken(token);
    if (!info) {
      throw new MCPAuthJwtVerificationError('jwt_verification_failed');
    }
    return info; // 인증 정보 객체 반환
  },
  {
    resource: 'https://api.example.com',
    audience: 'https://api.example.com', // 보안을 위한 대상(audience) 검증 활성화
    requiredScopes: ['read', 'write']
  }
);

MCP 서버에 Bearer 인증 적용하기

MCP 서버를 Bearer 인증으로 보호하려면, MCP 서버 인스턴스에 Bearer 인증 미들웨어를 적용해야 합니다.

const app = express();
app.use(mcpAuth.bearerAuth('jwt', {
  resource: 'https://api.example.com',
  audience: 'https://api.example.com', // 보안을 위한 대상(audience) 검증 활성화
  requiredScopes: ['read', 'write']
}));

이렇게 하면 모든 수신 요청이 구성된 Bearer 인증 설정에 따라 인증 및 인가되며, 인증 정보가 요청 컨텍스트에 제공됩니다.

이후 MCP 서버 구현에서 해당 정보를 사용할 수 있습니다:

// `authInfo`는 `req.auth` 객체에서 전달됨
server.registerTool(
  'whoami',
  {
    description: '현재 사용자 정보를 반환합니다',
    inputSchema: {},
  },
  ({ authInfo }) => {
    console.log(`인증된 사용자: ${authInfo.subject}`);
    return { subject: authInfo.subject };
  }
);