Cyber Catalyst Team
Deploy to HF Spaces with LFS
4782147
Raw
History Blame Contribute Delete
4.99 kB
import { NextRequest } from "next/server";
import { mcpOAuthRepository } from "@/lib/db/repository";
import { mcpClientsManager } from "lib/ai/mcp/mcp-manager";
import globalLogger from "logger";
import { colorize } from "consola/utils";
interface OAuthResponseOptions {
type: "success" | "error";
title: string;
heading: string;
message: string;
postMessageType: string;
postMessageData: Record<string, any>;
statusCode: number;
}
function createOAuthResponsePage(options: OAuthResponseOptions): Response {
const {
type,
title,
heading,
message,
postMessageType,
postMessageData,
statusCode,
} = options;
if (type === "success") {
logger.info("OAuth callback successful", message);
} else {
logger.error("OAuth callback failed", message);
}
const colorClass = type === "success" ? "success" : "error";
const color = type === "success" ? "#22c55e" : "#ef4444";
const html = `
<!DOCTYPE html>
<html>
<head>
<title>${title}</title>
<style>
body { font-family: system-ui, sans-serif; text-align: center; padding: 2rem; }
.${colorClass} { color: ${color}; }
</style>
</head>
<body>
<script>
try {
window.opener?.postMessage({
type: '${postMessageType}',
${Object.entries(postMessageData)
.map(([key, value]) => `${key}: '${value}'`)
.join(", ")}
}, window.location.origin);
} catch (e) {
console.error('Failed to post message:', e);
}
setTimeout(() => window.close(), 1000);
</script>
<div class="${colorClass}">
<h2>${heading}</h2>
<p>${message}</p>
<p>This window will close automatically.</p>
</div>
</body>
</html>`;
return new Response(html, {
status: statusCode,
headers: { "Content-Type": "text/html" },
});
}
const logger = globalLogger.withDefaults({
message: colorize("bgGreen", `MCP OAuth Callback: `),
});
/**
* OAuth callback endpoint for MCP servers
* Handles the authorization code exchange and token storage
*/
export async function GET(request: NextRequest) {
logger.info("OAuth callback received Authorization Code");
const { searchParams } = new URL(request.url);
const callbackData = {
code: searchParams.get("code") || undefined,
state: searchParams.get("state") || undefined,
error: searchParams.get("error") || undefined,
error_description: searchParams.get("error_description") || undefined,
};
// Handle OAuth error responses
if (callbackData.error) {
return createOAuthResponsePage({
type: "error",
title: "OAuth Error",
heading: "Authentication Failed",
message: `Error: ${callbackData.error}<br/>${callbackData.error_description || "Unknown error occurred"}`,
postMessageType: "MCP_OAUTH_ERROR",
postMessageData: {
error: callbackData.error,
error_description: callbackData.error_description || "Unknown error",
},
statusCode: 400,
});
}
// Validate required parameters
if (!callbackData.code || !callbackData.state) {
return createOAuthResponsePage({
type: "error",
title: "OAuth Error",
heading: "Authentication Failed",
message: "Missing required parameters",
postMessageType: "MCP_OAUTH_ERROR",
postMessageData: {
error: "invalid_request",
error_description: "Missing authorization code or state parameter",
},
statusCode: 400,
});
}
// Find the OAuth session by state
const session = await mcpOAuthRepository.getSessionByState(
callbackData.state,
);
if (!session) {
return createOAuthResponsePage({
type: "error",
title: "OAuth Error",
heading: "Authentication Failed",
message: "Invalid or expired session",
postMessageType: "MCP_OAUTH_ERROR",
postMessageData: {
error: "invalid_state",
error_description: "Invalid or expired state parameter",
},
statusCode: 400,
});
}
const client = await mcpClientsManager.getClient(session.mcpServerId);
try {
await client?.client.finishAuth(callbackData.code, callbackData.state);
await mcpClientsManager.refreshClient(session.mcpServerId);
return createOAuthResponsePage({
type: "success",
title: "OAuth Success",
heading: "Authentication Successful!",
message: "You can now close this window.",
postMessageType: "MCP_OAUTH_SUCCESS",
postMessageData: {
success: true,
},
statusCode: 200,
});
} catch (error: any) {
logger.error("OAuth callback failed", error);
return createOAuthResponsePage({
type: "error",
title: "OAuth Error",
heading: "Authentication Failed",
message: error.message || "Failed to complete the authentication process",
postMessageType: "MCP_OAUTH_ERROR",
postMessageData: {
error: "auth_failed",
error_description: "Failed to complete authentication",
},
statusCode: 500,
});
}
}