Add complete OAuth token refresh and sync solution
- Setup wizard with auto-detection of OpenClaw paths and Claude CLI - Token sync watcher (inotifywait) for real-time credential updates - Auto-refresh trigger timer that runs Claude CLI every 30 min - Supports Claude CLI in Docker container or on host - Temporary ANTHROPIC_BASE_URL override for container environments - Anthropic model configuration for OpenClaw - Auth profile management (fixes key vs access field) - Systemd services and timers for both sync and trigger - Comprehensive documentation and troubleshooting guides - Re-authentication notification system Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
109
tests/test-anthropic-connection.mjs
Normal file
109
tests/test-anthropic-connection.mjs
Normal file
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env node
|
||||
// test-anthropic-connection.mjs — Test Anthropic API connectivity with OAuth token
|
||||
// Usage: node test-anthropic-connection.mjs [token]
|
||||
// If no token provided, reads from oauth.json or .env
|
||||
|
||||
import https from 'node:https';
|
||||
import fs from 'node:fs';
|
||||
|
||||
// Find token
|
||||
let token = process.argv[2];
|
||||
|
||||
if (!token) {
|
||||
// Try oauth.json
|
||||
for (const path of [
|
||||
'/root/.openclaw/credentials/oauth.json',
|
||||
'/home/node/.openclaw/credentials/oauth.json',
|
||||
]) {
|
||||
try {
|
||||
const data = JSON.parse(fs.readFileSync(path, 'utf8'));
|
||||
token = data.anthropic?.access;
|
||||
if (token) { console.log(`Token from: ${path}`); break; }
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
|
||||
if (!token) {
|
||||
// Try .env
|
||||
try {
|
||||
const env = fs.readFileSync('/root/openclaw/.env', 'utf8');
|
||||
const match = env.match(/ANTHROPIC_OAUTH_TOKEN="?([^"\n]+)/);
|
||||
if (match) { token = match[1]; console.log('Token from: .env'); }
|
||||
} catch {}
|
||||
}
|
||||
|
||||
if (!token) {
|
||||
console.error('ERROR: No token found. Provide as argument or ensure oauth.json/.env exists.');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`Token: ${token.substring(0, 20)}...`);
|
||||
console.log('');
|
||||
|
||||
// Test API
|
||||
const body = JSON.stringify({
|
||||
model: 'claude-sonnet-4-20250514',
|
||||
max_tokens: 20,
|
||||
messages: [{ role: 'user', content: 'Say "hello" and nothing else.' }],
|
||||
});
|
||||
|
||||
const isOAuth = token.startsWith('sk-ant-oat');
|
||||
|
||||
const headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'anthropic-version': '2023-06-01',
|
||||
'Content-Length': Buffer.byteLength(body),
|
||||
};
|
||||
|
||||
if (isOAuth) {
|
||||
headers['Authorization'] = `Bearer ${token}`;
|
||||
// Claude Code identity headers required for OAuth
|
||||
headers['anthropic-beta'] = 'claude-code-20250219,oauth-2025-04-20';
|
||||
headers['user-agent'] = 'claude-cli/2.1.0';
|
||||
headers['x-app'] = 'cli';
|
||||
console.log('Auth: Bearer (OAuth token)');
|
||||
} else {
|
||||
headers['x-api-key'] = token;
|
||||
console.log('Auth: x-api-key');
|
||||
}
|
||||
|
||||
console.log('Sending test request to api.anthropic.com...');
|
||||
console.log('');
|
||||
|
||||
const req = https.request({
|
||||
hostname: 'api.anthropic.com',
|
||||
path: '/v1/messages',
|
||||
method: 'POST',
|
||||
headers,
|
||||
}, (res) => {
|
||||
let data = '';
|
||||
res.on('data', (chunk) => data += chunk);
|
||||
res.on('end', () => {
|
||||
console.log(`Status: ${res.statusCode}`);
|
||||
if (res.statusCode === 200) {
|
||||
try {
|
||||
const parsed = JSON.parse(data);
|
||||
const text = parsed.content?.[0]?.text || '';
|
||||
console.log(`Response: "${text}"`);
|
||||
console.log(`Model: ${parsed.model}`);
|
||||
console.log('');
|
||||
console.log('SUCCESS: Anthropic API connection working');
|
||||
} catch {
|
||||
console.log('Response:', data.substring(0, 200));
|
||||
}
|
||||
} else {
|
||||
console.log('Response:', data.substring(0, 500));
|
||||
console.log('');
|
||||
console.log('FAILED: API returned non-200 status');
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
req.on('error', (err) => {
|
||||
console.error('Connection error:', err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
req.write(body);
|
||||
req.end();
|
||||
Reference in New Issue
Block a user