UNPKG

@kya-os/mcp-i

Version:

The TypeScript MCP framework with identity features built-in

83 lines (82 loc) 3.01 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.apiKeyAuthMiddleware = apiKeyAuthMiddleware; const zod_1 = require("zod"); const apiKeyAuthMiddlewareConfigSchema = zod_1.z .object({ apiKey: zod_1.z.string().optional(), headerName: zod_1.z.string().optional(), validateApiKey: zod_1.z .function() .args(zod_1.z.string()) .returns(zod_1.z.promise(zod_1.z.boolean())) .optional(), }) .strict() .refine((config) => config.apiKey !== undefined || config.validateApiKey !== undefined, { message: "Either 'apiKey' or 'validateApiKey' must be provided", }) .refine((config) => !(config.apiKey !== undefined && config.validateApiKey !== undefined), { message: "'apiKey' and 'validateApiKey' are mutually exclusive - provide only one", }); const errorMessage = "Unauthorized: Missing or invalid API key"; /** * Middleware to authenticate requests using an API key. * @param config - Configuration object containing either a static API key or a function to validate the API key. * @returns Express middleware function. * * @example * ```ts * const middleware = apiKeyAuthMiddleware({ * apiKey: process.env.API_KEY!, * }); * ``` * * @example * ```ts * const middleware = apiKeyAuthMiddleware({ * validateApiKey: async (key) => { * return key === process.env.API_KEY!; * }, * }); * ``` */ function apiKeyAuthMiddleware(config) { // To do, we can maybe work on better error handling here, like typing the error messages etc const response = apiKeyAuthMiddlewareConfigSchema.safeParse(config); if (!response.success) { const hasApiKey = "apiKey" in config; const hasValidateApiKey = "validateApiKey" in config; if (hasApiKey && hasValidateApiKey) { throw new Error("'apiKey' and 'validateApiKey' are mutually exclusive - provide only one"); } else if (!hasApiKey && !hasValidateApiKey) { throw new Error("Either 'apiKey' or 'validateApiKey' must be provided"); } else { throw new Error(`Invalid configuration: ${response.error.message}`); } } const headerName = config.headerName ?? "x-api-key"; const apiKey = "apiKey" in config ? config.apiKey : undefined; const validateApiKey = "validateApiKey" in config ? config.validateApiKey : undefined; return async (req, res, next) => { const apiKeyHeader = req.header(headerName); if (!apiKeyHeader) { res.status(401).json({ error: errorMessage }); return; } if ("apiKey" in config && apiKeyHeader !== apiKey) { res.status(401).json({ error: errorMessage }); return; } if (validateApiKey) { const isValid = await validateApiKey(apiKeyHeader); if (!isValid) { res.status(401).json({ error: errorMessage }); return; } } next(); }; }