Files
openclaw-backups/skills/openclaw-self-healing/scripts/kakao-oauth-refresh.js

145 lines
4.9 KiB
JavaScript

#!/usr/bin/env node
/**
* Kakao OAuth Refresh Token Collector
*
* 1. Starts local server on :8080
* 2. Opens browser for authorization
* 3. Exchanges code for tokens
* 4. Saves refresh_token to openclaw.json
*/
const http = require('http');
const { spawn } = require('child_process');
const fs = require('fs');
const path = require('path');
const REST_API_KEY = process.env.KAKAO_REST_API_KEY || '4d7f36bbfa672c5e24582307de57f4e4';
const CLIENT_SECRET = process.env.KAKAO_CLIENT_SECRET;
const REDIRECT_URI = 'http://localhost:8080/callback';
const SCOPE = 'talk_calendar';
if (!CLIENT_SECRET) {
console.error('❌ KAKAO_CLIENT_SECRET environment variable not set');
process.exit(1);
}
const CONFIG_PATH = path.join(process.env.HOME, '.openclaw', 'openclaw.json');
// Authorization URL
const authUrl = `https://kauth.kakao.com/oauth/authorize?client_id=${REST_API_KEY}&redirect_uri=${encodeURIComponent(REDIRECT_URI)}&response_type=code&scope=${SCOPE}`;
console.log('📱 Kakao OAuth Refresh Token Collector\n');
console.log('🔗 Authorization URL:');
console.log(authUrl);
console.log('\n🌐 Opening browser...\n');
// Open browser
spawn('open', [authUrl]);
// Start callback server
const server = http.createServer(async (req, res) => {
const url = new URL(req.url, `http://localhost:8080`);
if (url.pathname === '/callback') {
const code = url.searchParams.get('code');
const error = url.searchParams.get('error');
if (error) {
res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
res.end(`<h1>❌ Authorization Failed</h1><p>Error: ${error}</p>`);
console.error('❌ Authorization failed:', error);
server.close();
process.exit(1);
}
if (!code) {
res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
res.end('<h1>❌ No code received</h1>');
console.error('❌ No authorization code received');
server.close();
process.exit(1);
}
console.log('✅ Authorization code received:', code);
console.log('🔄 Exchanging code for tokens...\n');
// Exchange code for tokens
try {
const tokenResponse = await fetch('https://kauth.kakao.com/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
},
body: new URLSearchParams({
grant_type: 'authorization_code',
client_id: REST_API_KEY,
client_secret: CLIENT_SECRET,
redirect_uri: REDIRECT_URI,
code: code
})
});
const tokens = await tokenResponse.json();
if (tokens.error) {
throw new Error(`Token exchange failed: ${tokens.error_description || tokens.error}`);
}
console.log('✅ Tokens received:');
console.log(` Access Token: ${tokens.access_token.substring(0, 20)}...`);
console.log(` Refresh Token: ${tokens.refresh_token.substring(0, 20)}...`);
console.log(` Expires in: ${tokens.expires_in}s (${tokens.expires_in / 3600}h)`);
console.log(` Refresh Token Expires in: ${tokens.refresh_token_expires_in}s (${tokens.refresh_token_expires_in / 86400}d)\n`);
// Save to openclaw.json
const config = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8'));
if (!config.env) config.env = {};
if (!config.env.vars) config.env.vars = {};
config.env.vars.KAKAO_ACCESS_TOKEN = tokens.access_token;
config.env.vars.KAKAO_REFRESH_TOKEN = tokens.refresh_token;
config.env.vars.KAKAO_TOKEN_EXPIRES_AT = new Date(Date.now() + tokens.expires_in * 1000).toISOString();
config.env.vars.KAKAO_REFRESH_TOKEN_EXPIRES_AT = new Date(Date.now() + tokens.refresh_token_expires_in * 1000).toISOString();
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
console.log('💾 Tokens saved to:', CONFIG_PATH);
console.log('✅ Done! Gateway restart required.\n');
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.end(`
<h1>✅ Success!</h1>
<p>Refresh token saved. You can close this window.</p>
<p>Next: Restart OpenClaw gateway.</p>
`);
server.close();
process.exit(0);
} catch (error) {
console.error('❌ Token exchange failed:', error.message);
res.writeHead(500, { 'Content-Type': 'text/html; charset=utf-8' });
res.end(`<h1>❌ Token Exchange Failed</h1><p>${error.message}</p>`);
server.close();
process.exit(1);
}
} else {
res.writeHead(404);
res.end('Not Found');
}
});
server.listen(8080, () => {
console.log('🚀 Callback server listening on http://localhost:8080');
console.log('⏳ Waiting for authorization...\n');
});
// Timeout after 5 minutes
setTimeout(() => {
console.log('\n⏰ Timeout after 5 minutes');
server.close();
process.exit(1);
}, 5 * 60 * 1000);