UNPKG

mcp-framework

Version:

Framework for building Model Context Protocol (MCP) servers in Typescript

74 lines (73 loc) 2.36 kB
import { logger } from "../../core/Logger.js"; import { DEFAULT_AUTH_ERROR } from "../types.js"; export const DEFAULT_API_KEY_HEADER_NAME = "X-API-Key"; /** * API key-based authentication provider */ export class APIKeyAuthProvider { config; constructor(config) { this.config = { headerName: DEFAULT_API_KEY_HEADER_NAME, ...config }; if (!this.config.keys?.length) { throw new Error("At least one API key is required"); } } /** * Get the number of configured API keys */ getKeyCount() { return this.config.keys.length; } /** * Get the configured header name */ getHeaderName() { return this.config.headerName; } async authenticate(req) { logger.debug(`API Key auth attempt from ${req.socket.remoteAddress}`); logger.debug(`All request headers: ${JSON.stringify(req.headers, null, 2)}`); const headerVariations = [ this.config.headerName, this.config.headerName.toLowerCase(), this.config.headerName.toUpperCase(), 'x-api-key', 'X-API-KEY', 'X-Api-Key' ]; logger.debug(`Looking for header variations: ${headerVariations.join(', ')}`); let apiKey; let matchedHeader; for (const [key, value] of Object.entries(req.headers)) { const lowerKey = key.toLowerCase(); if (headerVariations.some(h => h.toLowerCase() === lowerKey)) { apiKey = Array.isArray(value) ? value[0] : value; matchedHeader = key; break; } } if (!apiKey) { logger.debug(`API Key header missing}`); logger.debug(`Available headers: ${Object.keys(req.headers).join(', ')}`); return false; } logger.debug(`Found API key in header: ${matchedHeader}`); for (const validKey of this.config.keys) { if (apiKey === validKey) { logger.debug(`API Key authentication successful`); return true; } } logger.debug(`Invalid API Key provided`); return false; } getAuthError() { return { ...DEFAULT_AUTH_ERROR, message: "Invalid API key" }; } }