Reduce MCP OAuth debug detail

This commit is contained in:
2026-04-04 09:23:12 +08:00
parent 832035a087
commit 7cf8afab73

View File

@@ -93,37 +93,6 @@ type MCPOAuthFlowErrorReason =
const MAX_LOCK_RETRIES = 5 const MAX_LOCK_RETRIES = 5
/**
* OAuth query parameters that should be redacted from logs.
* These contain sensitive values that could enable CSRF or session fixation attacks.
*/
const SENSITIVE_OAUTH_PARAMS = [
'state',
'nonce',
'code_challenge',
'code_verifier',
'code',
]
/**
* Redacts sensitive OAuth query parameters from a URL for safe logging.
* Prevents exposure of state, nonce, code_challenge, code_verifier, and authorization codes.
*/
function redactSensitiveUrlParams(url: string): string {
try {
const parsedUrl = new URL(url)
for (const param of SENSITIVE_OAUTH_PARAMS) {
if (parsedUrl.searchParams.has(param)) {
parsedUrl.searchParams.set(param, '[REDACTED]')
}
}
return parsedUrl.toString()
} catch {
// Return as-is if not a valid URL
return url
}
}
function summarizeHeadersForDebug( function summarizeHeadersForDebug(
headers: Record<string, string> | undefined, headers: Record<string, string> | undefined,
): { ): {
@@ -1899,29 +1868,18 @@ export class ClaudeAuthProvider implements OAuthClientProvider {
// Extract and store scopes from the authorization URL for later use in token exchange // Extract and store scopes from the authorization URL for later use in token exchange
const scopes = authorizationUrl.searchParams.get('scope') const scopes = authorizationUrl.searchParams.get('scope')
logMCPDebug(
this.serverName,
`Authorization URL: ${redactSensitiveUrlParams(authorizationUrl.toString())}`,
)
logMCPDebug(this.serverName, `Scopes in URL: ${scopes || 'NOT FOUND'}`)
if (scopes) { if (scopes) {
this._scopes = scopes this._scopes = scopes
logMCPDebug( logMCPDebug(this.serverName, 'Captured scopes from authorization URL')
this.serverName,
`Captured scopes from authorization URL: ${scopes}`,
)
} else { } else {
// If no scope in URL, try to get it from metadata // If no scope in URL, try to get it from metadata
const metadataScope = getScopeFromMetadata(this._metadata) const metadataScope = getScopeFromMetadata(this._metadata)
if (metadataScope) { if (metadataScope) {
this._scopes = metadataScope this._scopes = metadataScope
logMCPDebug( logMCPDebug(this.serverName, 'Using scopes from metadata')
this.serverName,
`Using scopes from metadata: ${metadataScope}`,
)
} else { } else {
logMCPDebug(this.serverName, `No scopes available from URL or metadata`) logMCPDebug(this.serverName, 'No scopes available from URL or metadata')
} }
} }
@@ -1939,7 +1897,7 @@ export class ClaudeAuthProvider implements OAuthClientProvider {
if (existing) { if (existing) {
existing.stepUpScope = this._scopes existing.stepUpScope = this._scopes
storage.update(existingData) storage.update(existingData)
logMCPDebug(this.serverName, `Persisted step-up scope: ${this._scopes}`) logMCPDebug(this.serverName, 'Persisted step-up scope')
} }
} }
@@ -1960,8 +1918,6 @@ export class ClaudeAuthProvider implements OAuthClientProvider {
} }
logMCPDebug(this.serverName, `Redirecting to authorization URL`) logMCPDebug(this.serverName, `Redirecting to authorization URL`)
const redactedUrl = redactSensitiveUrlParams(urlString)
logMCPDebug(this.serverName, `Authorization URL: ${redactedUrl}`)
// Notify the UI about the authorization URL BEFORE opening the browser, // Notify the UI about the authorization URL BEFORE opening the browser,
// so users can see the URL as a fallback if the browser fails to open // so users can see the URL as a fallback if the browser fails to open
@@ -1970,7 +1926,7 @@ export class ClaudeAuthProvider implements OAuthClientProvider {
} }
if (!this.skipBrowserOpen) { if (!this.skipBrowserOpen) {
logMCPDebug(this.serverName, `Opening authorization URL: ${redactedUrl}`) logMCPDebug(this.serverName, 'Opening authorization URL')
const success = await openBrowser(urlString) const success = await openBrowser(urlString)
if (!success) { if (!success) {
@@ -1982,7 +1938,7 @@ export class ClaudeAuthProvider implements OAuthClientProvider {
} else { } else {
logMCPDebug( logMCPDebug(
this.serverName, this.serverName,
`Skipping browser open (skipBrowserOpen=true). URL: ${redactedUrl}`, 'Skipping browser open (skipBrowserOpen=true)',
) )
} }
} }
@@ -2035,7 +1991,7 @@ export class ClaudeAuthProvider implements OAuthClientProvider {
} }
storage.update(existingData) storage.update(existingData)
logMCPDebug(this.serverName, `Invalidated credentials (scope: ${scope})`) logMCPDebug(this.serverName, `Invalidated credentials (${scope})`)
} }
async saveDiscoveryState(state: OAuthDiscoveryState): Promise<void> { async saveDiscoveryState(state: OAuthDiscoveryState): Promise<void> {
@@ -2043,10 +1999,7 @@ export class ClaudeAuthProvider implements OAuthClientProvider {
const existingData = storage.read() || {} const existingData = storage.read() || {}
const serverKey = getServerKey(this.serverName, this.serverConfig) const serverKey = getServerKey(this.serverName, this.serverConfig)
logMCPDebug( logMCPDebug(this.serverName, 'Saving discovery state')
this.serverName,
`Saving discovery state (authServer: ${state.authorizationServerUrl})`,
)
// Persist only the URLs, NOT the full metadata blobs. // Persist only the URLs, NOT the full metadata blobs.
// authorizationServerMetadata alone is ~1.5-2KB per MCP server (every // authorizationServerMetadata alone is ~1.5-2KB per MCP server (every
@@ -2085,10 +2038,7 @@ export class ClaudeAuthProvider implements OAuthClientProvider {
const cached = data?.mcpOAuth?.[serverKey]?.discoveryState const cached = data?.mcpOAuth?.[serverKey]?.discoveryState
if (cached?.authorizationServerUrl) { if (cached?.authorizationServerUrl) {
logMCPDebug( logMCPDebug(this.serverName, 'Returning cached discovery state')
this.serverName,
`Returning cached discovery state (authServer: ${cached.authorizationServerUrl})`,
)
return { return {
authorizationServerUrl: cached.authorizationServerUrl, authorizationServerUrl: cached.authorizationServerUrl,