Add debug logging for OAuth flow troubleshooting
Add logging to track authorization flow steps and token introspection to help diagnose issues with separate mode authentication.
This commit is contained in:
parent
b32d638c87
commit
4fe137426b
2 changed files with 36 additions and 1 deletions
|
|
@ -18,6 +18,7 @@ import {
|
||||||
saveRefreshToken,
|
saveRefreshToken,
|
||||||
} from '../services/auth.js';
|
} from '../services/auth.js';
|
||||||
import { InvalidTokenError } from '@modelcontextprotocol/sdk/server/auth/errors.js';
|
import { InvalidTokenError } from '@modelcontextprotocol/sdk/server/auth/errors.js';
|
||||||
|
import { logger } from '../utils/logger.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of the OAuthRegisteredClientsStore interface using the existing client registration system
|
* Implementation of the OAuthRegisteredClientsStore interface using the existing client registration system
|
||||||
|
|
@ -67,6 +68,12 @@ export class EverythingAuthProvider implements OAuthServerProvider {
|
||||||
state: params.state,
|
state: params.state,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
logger.debug('Saved pending authorization', {
|
||||||
|
authorizationCode: authorizationCode.substring(0, 8) + '...',
|
||||||
|
clientId: client.client_id,
|
||||||
|
state: params.state?.substring(0, 8) + '...'
|
||||||
|
});
|
||||||
|
|
||||||
// TODO: should we use a different key, other than the authorization code, to store the pending authorization?
|
// TODO: should we use a different key, other than the authorization code, to store the pending authorization?
|
||||||
|
|
||||||
// You can redirect to another page, or you can send an html response directly
|
// You can redirect to another page, or you can send an html response directly
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { Request, Response } from "express";
|
import { Request, Response } from "express";
|
||||||
import { generateMcpTokens, readPendingAuthorization, saveMcpInstallation, saveRefreshToken, saveTokenExchange } from "../services/auth.js";
|
import { generateMcpTokens, readPendingAuthorization, saveMcpInstallation, saveRefreshToken, saveTokenExchange } from "../services/auth.js";
|
||||||
import { McpInstallation } from "../types.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
|
// 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
|
// authorization, to test the different flows
|
||||||
|
|
@ -266,6 +267,12 @@ export async function handleFakeAuthorizeRedirect(req: Request, res: Response) {
|
||||||
userId, // User ID from the authorization flow
|
userId, // User ID from the authorization flow
|
||||||
} = req.query;
|
} = 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
|
// This is where you'd exchange the upstreamAuthorizationCode for access/refresh tokens
|
||||||
// In this case, we're just going to fake it
|
// In this case, we're just going to fake it
|
||||||
const upstreamTokens = await fakeUpstreamTokenExchange(upstreamAuthorizationCode as string);
|
const upstreamTokens = await fakeUpstreamTokenExchange(upstreamAuthorizationCode as string);
|
||||||
|
|
@ -276,12 +283,21 @@ export async function handleFakeAuthorizeRedirect(req: Request, res: Response) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const pendingAuth = await readPendingAuthorization(mcpAuthorizationCode);
|
const pendingAuth = await readPendingAuthorization(mcpAuthorizationCode);
|
||||||
|
logger.debug('Reading pending authorization', {
|
||||||
|
mcpAuthorizationCode: mcpAuthorizationCode.substring(0, 8) + '...',
|
||||||
|
found: !!pendingAuth
|
||||||
|
});
|
||||||
|
|
||||||
if (!pendingAuth) {
|
if (!pendingAuth) {
|
||||||
throw new Error("No matching authorization found");
|
throw new Error("No matching authorization found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.debug('Generating MCP tokens');
|
||||||
const mcpTokens = generateMcpTokens();
|
const mcpTokens = generateMcpTokens();
|
||||||
|
logger.debug('MCP tokens generated', {
|
||||||
|
hasAccessToken: !!mcpTokens.access_token,
|
||||||
|
hasRefreshToken: !!mcpTokens.refresh_token
|
||||||
|
});
|
||||||
|
|
||||||
const mcpInstallation: McpInstallation = {
|
const mcpInstallation: McpInstallation = {
|
||||||
fakeUpstreamInstallation: {
|
fakeUpstreamInstallation: {
|
||||||
|
|
@ -294,25 +310,37 @@ export async function handleFakeAuthorizeRedirect(req: Request, res: Response) {
|
||||||
userId: (userId as string) || 'anonymous-user', // Include user ID from auth flow
|
userId: (userId as string) || 'anonymous-user', // Include user ID from auth flow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.debug('Saving MCP installation');
|
||||||
// Store the upstream authorization data
|
// Store the upstream authorization data
|
||||||
await saveMcpInstallation(mcpTokens.access_token, mcpInstallation);
|
await saveMcpInstallation(mcpTokens.access_token, mcpInstallation);
|
||||||
|
logger.debug('MCP installation saved');
|
||||||
|
|
||||||
// Store the refresh token -> access token mapping
|
// Store the refresh token -> access token mapping
|
||||||
if (mcpTokens.refresh_token) {
|
if (mcpTokens.refresh_token) {
|
||||||
|
logger.debug('Saving refresh token mapping');
|
||||||
await saveRefreshToken(mcpTokens.refresh_token, mcpTokens.access_token);
|
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
|
// Store the token exchange data
|
||||||
await saveTokenExchange(mcpAuthorizationCode, {
|
await saveTokenExchange(mcpAuthorizationCode, {
|
||||||
mcpAccessToken: mcpTokens.access_token,
|
mcpAccessToken: mcpTokens.access_token,
|
||||||
alreadyUsed: false,
|
alreadyUsed: false,
|
||||||
});
|
});
|
||||||
|
logger.debug('Token exchange data saved');
|
||||||
|
|
||||||
// Redirect back to the original application with the authorization code and state
|
// Redirect back to the original application with the authorization code and state
|
||||||
const redirectUrl = pendingAuth.state ?
|
const redirectUrl = pendingAuth.state ?
|
||||||
`${pendingAuth.redirectUri}?code=${mcpAuthorizationCode}&state=${pendingAuth.state}` :
|
`${pendingAuth.redirectUri}?code=${mcpAuthorizationCode}&state=${pendingAuth.state}` :
|
||||||
`${pendingAuth.redirectUri}?code=${mcpAuthorizationCode}`;
|
`${pendingAuth.redirectUri}?code=${mcpAuthorizationCode}`;
|
||||||
|
|
||||||
|
logger.debug('Redirecting to callback', {
|
||||||
|
redirectUrl,
|
||||||
|
hasState: !!pendingAuth.state
|
||||||
|
});
|
||||||
res.redirect(redirectUrl);
|
res.redirect(redirectUrl);
|
||||||
|
logger.debug('Redirect completed');
|
||||||
};
|
};
|
||||||
|
|
||||||
function fakeUpstreamTokenExchange(
|
function fakeUpstreamTokenExchange(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue