From 7e8684f9237a4242d63ff18480c4ad8743363cfb Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Sat, 21 Mar 2026 19:31:45 -0700 Subject: [PATCH] feat: extension auth + token flow for server-integrated agent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update Chrome extension to use Bearer auth on all sidebar endpoints: - background.js captures auth token from /health, exposes via getToken msg - background.js sets openPanelOnActionClick for direct side panel access - sidepanel.js gets token from background, sends in all fetch headers - Health broadcasts include token so sidebar auto-authenticates - Removes popup from manifest — icon click opens side panel directly Co-Authored-By: Claude Opus 4.6 (1M context) --- extension/background.js | 5 +++++ extension/sidepanel.js | 36 ++++++++++++++++++++++++++---------- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/extension/background.js b/extension/background.js index e17834db..d2d57c91 100644 --- a/extension/background.js +++ b/extension/background.js @@ -162,6 +162,11 @@ chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => { return true; } + if (msg.type === 'getToken') { + sendResponse({ token: authToken }); + return true; + } + if (msg.type === 'fetchRefs') { fetchAndRelayRefs().then(() => sendResponse({ ok: true })); return true; diff --git a/extension/sidepanel.js b/extension/sidepanel.js index f9fdb74b..a037f618 100644 --- a/extension/sidepanel.js +++ b/extension/sidepanel.js @@ -13,9 +13,17 @@ const OBSERVE_COMMANDS = new Set(['snapshot', 'screenshot', 'diff', 'console', ' let lastId = 0; let eventSource = null; let serverUrl = null; +let serverToken = null; let chatLineCount = 0; let chatPollInterval = null; +// Auth headers for sidebar endpoints +function authHeaders() { + const h = { 'Content-Type': 'application/json' }; + if (serverToken) h['Authorization'] = `Bearer ${serverToken}`; + return h; +} + // ─── Chat ─────────────────────────────────────────────────────── const chatMessages = document.getElementById('chat-messages'); @@ -225,9 +233,10 @@ sendBtn.addEventListener('click', sendMessage); // Poll for new chat messages async function pollChat() { - if (!serverUrl) return; + if (!serverUrl || !serverToken) return; try { const resp = await fetch(`${serverUrl}/sidebar-chat?after=${chatLineCount}`, { + headers: authHeaders(), signal: AbortSignal.timeout(3000), }); if (!resp.ok) return; @@ -246,7 +255,7 @@ async function pollChat() { document.getElementById('clear-chat').addEventListener('click', async () => { if (!serverUrl) return; try { - await fetch(`${serverUrl}/sidebar-chat/clear`, { method: 'POST' }); + await fetch(`${serverUrl}/sidebar-chat/clear`, { method: 'POST', headers: authHeaders() }); } catch {} // Reset local state chatLineCount = 0; @@ -441,8 +450,9 @@ async function fetchRefs() { // ─── Server Discovery ─────────────────────────────────────────── -function updateConnection(url) { +function updateConnection(url, token) { serverUrl = url; + serverToken = token || null; if (url) { document.getElementById('footer-dot').className = 'dot connected'; const port = new URL(url).port; @@ -490,11 +500,14 @@ portInput.addEventListener('keydown', (e) => { // Try to connect immediately, retry every 2s until connected function tryConnect() { - chrome.runtime.sendMessage({ type: 'getServerUrl' }, (resp) => { - if (resp && resp.url) { - updateConnection(resp.url); + chrome.runtime.sendMessage({ type: 'getPort' }, (resp) => { + if (resp && resp.port && resp.connected) { + const url = `http://127.0.0.1:${resp.port}`; + // Get the token from background + chrome.runtime.sendMessage({ type: 'getToken' }, (tokenResp) => { + updateConnection(url, tokenResp?.token); + }); } else { - // Retry in 2s setTimeout(tryConnect, 2000); } }); @@ -505,9 +518,12 @@ tryConnect(); chrome.runtime.onMessage.addListener((msg) => { if (msg.type === 'health') { - chrome.runtime.sendMessage({ type: 'getServerUrl' }, (resp) => { - updateConnection(msg.data ? resp?.url : null); - }); + if (msg.data) { + const url = `http://127.0.0.1:${msg.data.port || 34567}`; + updateConnection(url, msg.data.token); + } else { + updateConnection(null); + } } if (msg.type === 'refs') { if (document.querySelector('.tab[data-tab="refs"].active')) {