import { Request, Response } from "express"; import { generateMcpTokens, readPendingAuthorization, saveMcpInstallation, saveRefreshToken, saveTokenExchange } from "../services/auth.js"; import { McpInstallation } from "../types.js"; import { logger } from "../utils/logger.js"; // this module has a fake upstream auth server that returns a fake auth code, it also allows you to authorize or fail // authorization, to test the different flows // TODO: make an implementation of this using the ProxyAuthProvider // This is mocking an upstream auth server. This wouldn't normally be in the same server as the MCP auth server export async function handleFakeAuthorize(req: Request, res: Response) { // get the redirect_uri and state from the query params const { redirect_uri, state } = req.query; // Set a more permissive CSP for auth pages to allow inline styles and scripts res.setHeader('Content-Security-Policy', [ "default-src 'self'", "style-src 'self' 'unsafe-inline'", // Allow inline styles for auth page styling "script-src 'self' 'unsafe-inline'", // Allow inline scripts for auth page functionality "object-src 'none'", "frame-ancestors 'none'", "form-action 'self'", "base-uri 'self'" ].join('; ')); res.send(` Upstream Provider Authentication

Upstream Authentication

Please verify your identity with the upstream provider

Your User Identity

Loading...
Testing Multiple Users: Open this page in different browser windows or incognito tabs to simulate different users. Each will have their own unique User ID and separate MCP sessions.
`); } // This is the callback URL that the upstream auth server will redirect to after authorization export async function handleFakeAuthorizeRedirect(req: Request, res: Response) { const { // The state returned from the upstream auth server is actually the authorization code state: mcpAuthorizationCode, code: upstreamAuthorizationCode, userId, // User ID from the authorization flow } = req.query; logger.debug('Fake auth redirect received', { mcpAuthorizationCode: typeof mcpAuthorizationCode === 'string' ? mcpAuthorizationCode.substring(0, 8) + '...' : mcpAuthorizationCode, upstreamAuthorizationCode: typeof upstreamAuthorizationCode === 'string' ? upstreamAuthorizationCode.substring(0, 8) + '...' : upstreamAuthorizationCode, userId }); // This is where you'd exchange the upstreamAuthorizationCode for access/refresh tokens // In this case, we're just going to fake it const upstreamTokens = await fakeUpstreamTokenExchange(upstreamAuthorizationCode as string); // Validate that it's a string if (typeof mcpAuthorizationCode !== "string") { throw new Error("Invalid authorization code"); } const pendingAuth = await readPendingAuthorization(mcpAuthorizationCode); logger.debug('Reading pending authorization', { mcpAuthorizationCode: mcpAuthorizationCode.substring(0, 8) + '...', found: !!pendingAuth }); if (!pendingAuth) { throw new Error("No matching authorization found"); } logger.debug('Generating MCP tokens'); const mcpTokens = generateMcpTokens(); logger.debug('MCP tokens generated', { hasAccessToken: !!mcpTokens.access_token, hasRefreshToken: !!mcpTokens.refresh_token }); const mcpInstallation: McpInstallation = { fakeUpstreamInstallation: { fakeAccessTokenForDemonstration: upstreamTokens.access_token, fakeRefreshTokenForDemonstration: upstreamTokens.refresh_token, }, mcpTokens, clientId: pendingAuth.clientId, issuedAt: Date.now() / 1000, userId: (userId as string) || 'anonymous-user', // Include user ID from auth flow } logger.debug('Saving MCP installation'); // Store the upstream authorization data await saveMcpInstallation(mcpTokens.access_token, mcpInstallation); logger.debug('MCP installation saved'); // Store the refresh token -> access token mapping if (mcpTokens.refresh_token) { logger.debug('Saving refresh token mapping'); await saveRefreshToken(mcpTokens.refresh_token, mcpTokens.access_token); logger.debug('Refresh token mapping saved'); } logger.debug('Saving token exchange data'); // Store the token exchange data await saveTokenExchange(mcpAuthorizationCode, { mcpAccessToken: mcpTokens.access_token, alreadyUsed: false, }); logger.debug('Token exchange data saved'); // Redirect back to the original application with the authorization code and state const redirectUrl = pendingAuth.state ? `${pendingAuth.redirectUri}?code=${mcpAuthorizationCode}&state=${pendingAuth.state}` : `${pendingAuth.redirectUri}?code=${mcpAuthorizationCode}`; logger.debug('Redirecting to callback', { redirectUrl, hasState: !!pendingAuth.state }); res.redirect(redirectUrl); logger.debug('Redirect completed'); }; function fakeUpstreamTokenExchange( authorizationCode: string, ): Promise<{ access_token: string; refresh_token: string }> { // just return the authorization code with a suffix return new Promise((resolve) => { resolve({ access_token: `${authorizationCode}-exchanged-for-access-token`, refresh_token: `${authorizationCode}-exchanged-for-refresh-token`, }); }); }