#!/usr/bin/env node
/**
* TRACE API KEY GENERATION FOR BANK LEUMI TEST ENV
*
* This script traces how the API key is generated for Bank Leumi BL Test Env
* to understand why it's not being created with the expected value:
* 57ade50e-c9a8-49f3-8ce7-28d44536a669:24223:1
*/
const fetch = require('node-fetch');
const https = require('https');
const { spawn } = require('child_process');
const express = require('express');
const crypto = require('crypto');
// Disable SSL verification for local testing
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
const LOCAL_MCP_URL = 'https://localhost:3003';
function base64URLEncode(str) {
return str.toString('base64')
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
}
function generateCodeChallenge() {
const codeVerifier = base64URLEncode(crypto.randomBytes(32));
const codeChallenge = base64URLEncode(crypto.createHash('sha256').update(codeVerifier).digest());
return { codeVerifier, codeChallenge };
}
class ApiKeyTracer {
constructor() {
this.username = 'david+allcloud@umbrellacost.com';
this.password = 'Dsamsung1!';
this.accessToken = null;
this.server = null;
this.port = 3004;
this.codeVerifier = null;
}
async startCallbackServer() {
return new Promise((resolve) => {
const app = express();
app.get('/', (req, res) => {
res.send(`
<html>
<head><title>API Key Tracer</title></head>
<body style="font-family: Arial; text-align: center; padding: 50px;">
<h1>🔍 Tracing API Key Generation</h1>
<p>For Bank Leumi BL Test Env</p>
</body>
</html>
`);
});
app.get('/callback', (req, res) => {
const { code, error } = req.query;
if (error) {
res.send(`<html><body>Error: ${error}</body></html>`);
return;
}
if (code) {
res.send(`
<html>
<body style="font-family: Arial; text-align: center; padding: 50px;">
<h1 style="color: green;">✅ OAuth Success!</h1>
<p>Tracing API key generation...</p>
<script>setTimeout(() => window.close(), 2000);</script>
</body>
</html>
`);
resolve(code);
}
});
this.server = app.listen(this.port, () => {
console.log(`📡 Callback server listening on port ${this.port}`);
});
});
}
async registerOAuthClient() {
const redirectUri = `http://localhost:${this.port}/callback`;
const clientData = {
client_name: 'API Key Tracer',
redirect_uris: [redirectUri],
grant_types: ['authorization_code'],
response_types: ['code'],
scope: 'openid profile email'
};
const response = await fetch(`${LOCAL_MCP_URL}/register`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(clientData),
agent: new https.Agent({
rejectUnauthorized: false
})
});
if (!response.ok) {
throw new Error(`Client registration failed: ${response.status}`);
}
const client = await response.json();
console.log(`✅ Client registered: ${client.client_id}`);
return { clientId: client.client_id, redirectUri };
}
async performOAuthFlow(clientId, redirectUri) {
const { codeVerifier, codeChallenge } = generateCodeChallenge();
this.codeVerifier = codeVerifier;
const authUrl = `${LOCAL_MCP_URL}/authorize?` + new URLSearchParams({
response_type: 'code',
client_id: clientId,
redirect_uri: redirectUri,
state: 'api_key_trace',
code_challenge: codeChallenge,
code_challenge_method: 'S256',
scope: 'openid profile email'
});
console.log('🌐 Opening browser for authentication...');
this.openBrowser(authUrl);
return true;
}
openBrowser(url) {
const platform = process.platform;
let command;
if (platform === 'darwin') {
command = 'open';
} else if (platform === 'win32') {
command = 'start';
} else {
command = 'xdg-open';
}
spawn(command, [url], { detached: true, stdio: 'ignore' });
}
async exchangeCodeForToken(authorizationCode, clientId, redirectUri) {
const response = await fetch(`${LOCAL_MCP_URL}/oauth/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
grant_type: 'authorization_code',
code: authorizationCode,
redirect_uri: redirectUri,
client_id: clientId,
code_verifier: this.codeVerifier
}),
agent: new https.Agent({
rejectUnauthorized: false
})
});
if (response.ok) {
const tokenData = await response.json();
this.accessToken = tokenData.access_token;
console.log(`✅ Token obtained successfully`);
return tokenData;
} else {
const error = await response.text();
throw new Error(`Token exchange failed: ${error}`);
}
}
async makeApiCall(toolName, args, description) {
const request = {
jsonrpc: '2.0',
method: 'tools/call',
params: {
name: toolName,
arguments: args
},
id: Math.floor(Math.random() * 1000)
};
console.log(`\n📤 ${description}`);
console.log(` Tool: ${toolName}`);
console.log(` Arguments:`, JSON.stringify(args, null, 2));
const startTime = Date.now();
const response = await fetch(`${LOCAL_MCP_URL}/mcp`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.accessToken}`,
'Content-Type': 'application/json',
'Accept': 'application/json, text/event-stream'
},
body: JSON.stringify(request),
agent: new https.Agent({
rejectUnauthorized: false
})
});
const time = Date.now() - startTime;
if (!response.ok) {
console.log(`❌ ${description} FAILED: ${response.status}`);
const error = await response.text();
console.log(' Error:', error);
return null;
}
let data;
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('text/event-stream')) {
const responseText = await response.text();
const lines = responseText.split('\n');
for (const line of lines) {
if (line.startsWith('data: ')) {
const jsonStr = line.substring(6).trim();
if (jsonStr && jsonStr !== '[DONE]') {
try {
data = JSON.parse(jsonStr);
break;
} catch (parseError) {}
}
}
}
} else {
data = await response.json();
}
console.log(`✅ ${description} SUCCESS (${time}ms)`);
return data;
}
async traceApiKeyGeneration() {
if (!this.accessToken) {
console.log('❌ No bearer token available');
return false;
}
console.log(`\n🔍 TRACING API KEY GENERATION`);
console.log(`🔑 Bearer Token: ${this.accessToken.substring(0, 50)}...`);
console.log(`\n📋 Expected Result:`);
console.log(` API Key: 57ade50e-c9a8-49f3-8ce7-28d44536a669:24223:1`);
console.log(` Account Key: 24223`);
console.log(` Division ID: 1`);
console.log(` Customer: Bank Leumi BL Test Env`);
try {
// Step 1: Call the recommendations endpoint with specific query
console.log('\n=== STEP 1: Call Recommendations with Bank Leumi Query ===');
const recommendationsData = await this.makeApiCall('api__api_v2_recommendations_list', {
userQuery: 'show me recommendations for Bank Leumi BL Test Env',
daysBack: 30,
pageSize: 5,
includeClosedAndDone: false
}, 'Get recommendations with Bank Leumi query');
if (recommendationsData && recommendationsData.result && recommendationsData.result.content) {
const text = recommendationsData.result.content[0]?.text || '';
// Extract detected customer info
const customerMatch = text.match(/\*\*Customer:\*\* ([^\n]+)/);
const accountMatch = text.match(/account[^0-9]*([0-9]+)/i);
if (customerMatch) {
console.log(`\n🎯 Detected Customer: ${customerMatch[1]}`);
}
if (accountMatch) {
console.log(`🔑 Detected Account Key: ${accountMatch[1]}`);
}
}
// Step 2: Check available customers from plain-sub-users
console.log('\n=== STEP 2: Get Available Customers ===');
const customersData = await this.makeApiCall('api__users_plain_sub_users', {
userQuery: 'Bank Leumi'
}, 'Get customer divisions for Bank Leumi');
if (customersData && customersData.result && customersData.result.content) {
const text = customersData.result.content[0]?.text || '';
console.log('\n📊 Customer Data:');
// Extract Bank Leumi accounts
const bankLeumiSection = text.match(/Bank Leumi[^\n]*\n([^]*?)(?=\n\n|\n\*\*|$)/);
if (bankLeumiSection) {
console.log(bankLeumiSection[0]);
}
}
// Step 3: Try different parameter combinations
console.log('\n=== STEP 3: Test Different Parameter Combinations ===');
// Test with customer_account_key directly
console.log('\n--- Test A: With customer_account_key=24223 ---');
await this.makeApiCall('api__api_v2_recommendations_list', {
customer_account_key: '24223',
customer_division_id: '1',
daysBack: 30,
pageSize: 5
}, 'Test with explicit customer_account_key');
// Test with accountId and divisionId
console.log('\n--- Test B: With accountId and divisionId ---');
await this.makeApiCall('api__api_v2_recommendations_list', {
accountId: '009671033607', // AWS account ID for Bank Leumi
divisionId: '1',
daysBack: 30,
pageSize: 5
}, 'Test with accountId and divisionId');
// Step 4: Check what the server logs show
console.log('\n=== STEP 4: Analysis ===');
console.log('🔍 Check the server logs for:');
console.log(' 1. [MSP-CHECK] messages to see if customer detection runs');
console.log(' 2. [CUSTOMER-DETECTION] messages to see pattern matching');
console.log(' 3. [API-KEY] messages to see how the key is built');
console.log(' 4. "Using API key" messages to see final key format');
console.log('\n📝 Key Questions:');
console.log(' - Is authMethod set correctly for OAuth sessions?');
console.log(' - Is customer detection logic running?');
console.log(' - Are customer_account_key and customer_division_id being passed to API client?');
console.log(' - Is getAuthHeaders receiving the customer parameters?');
console.log('\n✅ API Key Trace Complete!');
console.log('📋 Check server logs for detailed trace information');
return true;
} catch (error) {
console.log('❌ Trace Error:', error.message);
return false;
}
}
cleanup() {
if (this.server) {
this.server.close();
}
}
async run() {
try {
console.log('🔍 API Key Generation Tracer Starting...\n');
const serverPromise = this.startCallbackServer();
const { clientId, redirectUri } = await this.registerOAuthClient();
const flowStarted = await this.performOAuthFlow(clientId, redirectUri);
if (!flowStarted) {
throw new Error('Failed to start OAuth flow');
}
console.log('⏳ Waiting for authentication...');
console.log(' Please login with: david+allcloud@umbrellacost.com');
const timeoutPromise = new Promise((_, reject) =>
setTimeout(() => reject(new Error('OAuth timeout after 5 minutes')), 300000)
);
const authorizationCode = await Promise.race([serverPromise, timeoutPromise]);
if (authorizationCode) {
const tokenData = await this.exchangeCodeForToken(authorizationCode, clientId, redirectUri);
if (tokenData) {
await this.traceApiKeyGeneration();
}
}
} catch (error) {
console.error('❌ Error:', error.message);
} finally {
this.cleanup();
}
}
}
// Handle graceful shutdown
process.on('SIGINT', () => {
console.log('\n🛑 Interrupted - cleaning up...');
process.exit(0);
});
const tracer = new ApiKeyTracer();
tracer.run();