Skip to content

Instantly share code, notes, and snippets.

@vanpelt
Last active July 1, 2025 12:48
Show Gist options
  • Save vanpelt/87932a5707509aa6a090027bfd8da5a1 to your computer and use it in GitHub Desktop.
Save vanpelt/87932a5707509aa6a090027bfd8da5a1 to your computer and use it in GitHub Desktop.
Smart OAuth Proxy for Cloudflare Container Terminal - Auto-detects and forwards OAuth callbacks
#!/usr/bin/env node
/**
* Smart OAuth Proxy for Cloudflare Container Terminal
*
* This proxy automatically detects OAuth callback ports and forwards them
* to your containerized terminal, enabling seamless authentication for
* CLI tools like Gemini that require localhost callbacks.
*
* Usage: npx https://gist.githubusercontent.com/[gist-url]/smart-oauth-proxy.js [container-url]
* Example: npx https://bit.ly/cf-oauth-proxy http://localhost:8787
*/
const http = require('http');
const https = require('https');
const url = require('url');
const net = require('net');
const CONTAINER_URL = process.argv[2] || 'http://localhost:8787';
const SANDBOX_SLUG = process.argv[3] || 'demo';
// Active servers by port
const activeServers = {};
let portCheckInterval;
function log(message, color = 'reset') {
const colors = {
red: '\x1b[31m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
magenta: '\x1b[35m',
cyan: '\x1b[36m',
reset: '\x1b[0m'
};
console.log(`${colors[color]}${message}${colors.reset}`);
}
function makeHttpRequest(targetUrl, req, res) {
const originalPort = req.headers['x-original-port'];
log(`🔄 Forwarding OAuth callback to container (target port: ${originalPort})`, 'blue');
log(`🔍 Original request URL: ${req.url}`, 'cyan');
// Forward to the container's oauth2callback endpoint
// req.url already includes the path and query string, so just append it
const containerOAuthUrl = `${CONTAINER_URL}/api/sandbox/${SANDBOX_SLUG}${req.url}`;
log(`🔍 Forwarding to: ${containerOAuthUrl}`, 'cyan');
const containerUrl = url.parse(containerOAuthUrl);
const protocol = containerUrl.protocol === 'https:' ? https : http;
const proxyReq = protocol.request({
hostname: containerUrl.hostname,
port: containerUrl.port,
path: containerUrl.path,
method: req.method,
headers: {
...req.headers,
'x-forwarded-for': req.connection.remoteAddress,
'x-forwarded-proto': 'http',
'x-original-port': originalPort,
'x-target-port': originalPort // Tell container which port to forward to
}
}, (proxyRes) => {
log(`✅ Container responded: ${proxyRes.statusCode}`, 'green');
// Forward response headers
Object.keys(proxyRes.headers).forEach(key => {
res.setHeader(key, proxyRes.headers[key]);
});
res.statusCode = proxyRes.statusCode;
proxyRes.pipe(res);
proxyRes.on('end', () => {
log(`📤 OAuth callback completed for port ${originalPort}`, 'green');
});
});
proxyReq.on('error', (err) => {
log(`❌ Proxy error: ${err.message}`, 'red');
res.statusCode = 500;
res.end(`OAuth proxy error: ${err.message}`);
});
// Forward request body if present
req.pipe(proxyReq);
}
function createProxyServer(port) {
if (activeServers[port]) {
return; // Already listening on this port
}
const server = http.createServer((req, res) => {
// Add port info to headers for tracking
req.headers['x-original-port'] = port.toString();
log(`📥 OAuth callback received on port ${port}: ${req.method} ${req.url}`, 'cyan');
makeHttpRequest(CONTAINER_URL, req, res);
});
server.listen(port, 'localhost', () => {
log(`✅ OAuth proxy listening on localhost:${port}`, 'green');
activeServers[port] = server;
});
server.on('error', (err) => {
if (err.code === 'EADDRINUSE') {
log(`⚠️ Port ${port} already in use (probably by OAuth client) - that's perfect!`, 'yellow');
} else {
log(`❌ Server error on port ${port}: ${err.message}`, 'red');
}
delete activeServers[port];
});
return server;
}
async function pollContainerForPortInfo() {
try {
const response = await new Promise((resolve, reject) => {
const reqUrl = `${CONTAINER_URL}/api/sandbox/${SANDBOX_SLUG}/oauth-port-info`;
const urlObj = url.parse(reqUrl);
const protocol = urlObj.protocol === 'https:' ? https : http;
const req = protocol.request({
hostname: urlObj.hostname,
port: urlObj.port,
path: urlObj.path,
method: 'GET'
}, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => {
try {
resolve(JSON.parse(data));
} catch (e) {
log(`❌ Failed to parse JSON response: ${data}`, 'red');
resolve(null);
}
});
});
req.on('error', (err) => {
log(`❌ Request error: ${err.message}`, 'red');
resolve(null);
});
req.setTimeout(1000, () => {
log(`⏰ Request timeout`, 'yellow');
resolve(null);
});
req.end();
});
if (response && response.port) {
const port = parseInt(response.port);
if (!activeServers[port] && port >= 1024 && port <= 65535) {
log(`📡 Container reported OAuth port: ${port}`, 'blue');
createProxyServer(port);
}
} else {
log(`📡 Polling container... (no port detected yet)`, 'cyan');
}
} catch (e) {
log(`❌ Polling error: ${e.message}`, 'red');
}
}
function startMonitoring() {
log('🔍 Starting container polling...', 'yellow');
// Initial port detection
pollContainerForPortInfo();
// Periodic monitoring - only poll container for port info
portCheckInterval = setInterval(() => {
pollContainerForPortInfo();
}, 2000);
}
function shutdown() {
log('\n🛑 Shutting down OAuth proxy...', 'yellow');
if (portCheckInterval) {
clearInterval(portCheckInterval);
}
Object.values(activeServers).forEach(server => {
server.close();
});
log('✅ OAuth proxy stopped', 'green');
process.exit(0);
}
function printInstructions() {
console.log('');
log('🔐 Smart OAuth Proxy for Cloudflare Container Terminal', 'blue');
log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', 'blue');
console.log('');
log(`📡 Container URL: ${CONTAINER_URL}`, 'cyan');
log(`🏷️ Sandbox: ${SANDBOX_SLUG}`, 'cyan');
console.log('');
log('This proxy polls the container for OAuth port info and forwards', 'yellow');
log('callbacks to your container, enabling authentication for CLI tools like:', 'yellow');
console.log('');
log('• Gemini CLI (gemini auth login)', 'green');
log('• GitHub CLI (gh auth login)', 'green');
log('• Google Cloud CLI (gcloud auth login)', 'green');
log('• And other OAuth-enabled CLI tools', 'green');
console.log('');
log('🚀 Ready! Run your OAuth commands in the container terminal.', 'green');
log(' The proxy will automatically handle the callbacks.', 'green');
console.log('');
log('Press Ctrl+C to stop the proxy', 'yellow');
console.log('');
}
// Main execution
if (require.main === module) {
printInstructions();
startMonitoring();
// Graceful shutdown
process.on('SIGINT', shutdown);
process.on('SIGTERM', shutdown);
}
module.exports = { createProxyServer };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment