import type { Request, Response, NextFunction } from "express";
import type { AuthConfig } from "../config/schema.js";
import logger from "../utils/logger.js";
export function createAuthMiddleware(authConfig: AuthConfig) {
return (req: Request, res: Response, next: NextFunction): void => {
// Find the most specific auth config for this endpoint.
// Use originalUrl to get the full path (req.path is stripped when
// middleware is mounted at a sub-path via app.use("/mcp", ...)).
const fullPath = req.originalUrl.split("?")[0];
// Only apply auth to MCP endpoints
if (!fullPath.startsWith("/mcp")) {
next();
return;
}
let endpointAuth = authConfig.endpoints[fullPath];
// Try prefix matching for parameterized routes
if (!endpointAuth) {
const prefixes = Object.keys(authConfig.endpoints)
.filter((p) => fullPath.startsWith(p))
.sort((a, b) => b.length - a.length);
if (prefixes.length > 0) {
endpointAuth = authConfig.endpoints[prefixes[0]];
}
}
// Fall back to default
const config = endpointAuth ?? authConfig.default;
if (!config.enabled) {
next();
return;
}
const authHeader = req.headers.authorization;
if (!authHeader) {
logger.warn("Missing authorization header", { path: fullPath });
res.status(401).json({ error: "Authorization required" });
return;
}
const [scheme, token] = authHeader.split(" ");
if (scheme !== "Bearer" || !token) {
logger.warn("Invalid authorization scheme", { path: fullPath });
res.status(401).json({ error: "Bearer token required" });
return;
}
if (token !== config.token) {
logger.warn("Invalid token", { path: fullPath });
res.status(403).json({ error: "Invalid token" });
return;
}
next();
};
}