Skip to content

fix(auth): read the HttpOnly Slack d cookie for import-chrome - #160

Closed
arnaud-gp wants to merge 1 commit into
stablyai:mainfrom
arnaud-gp:fix/chrome-import-httponly-cookie
Closed

arnaud-gp wants to merge 1 commit into
stablyai:mainfrom
arnaud-gp:fix/chrome-import-httponly-cookie

Conversation

@arnaud-gp

Copy link
Copy Markdown

Problem

agent-slack auth import-chrome always failed on macOS with a single generic message:

Could not extract tokens from Chrome. Open Slack in Chrome and ensure you're logged in.

It failed even with a signed-in Slack tab open and Allow JavaScript from Apple Events enabled, because src/auth/chrome.ts read the d cookie through the page context:

document.cookie.split('; ').find(c => c.startsWith('d='))

Slack sets d as HttpOnly, so document.cookie never contains it. Verified against a real profile:

sqlite> select host_key, name, is_httponly from cookies where name='d' and host_key like '%slack.com';
.slack.com|d|1

extractFromChrome() therefore bailed at its first check (!cookie.startsWith("xoxd-")) on every run, and the surrounding catch { return null } collapsed every other cause — no Slack tab, Apple Events disabled, missing Automation consent — into the same message.

The Brave and Slack-desktop paths already do this correctly: they read the cookie store and decrypt with the Safe Storage keychain password. Chrome was the odd one out.

What Changed

  • src/auth/chrome.ts: read the d cookie from Chrome's cookie store (Default plus Profile N, both Cookies and Network/Cookies) and decrypt it with the Chrome Safe Storage keychain password, reusing decryptChromiumCookieValue. The DB is copied with its -wal/-shm siblings before reading, so a running Chrome neither blocks the read nor hides recent writes.
  • Replaced the blanket catch { return null } with typed, actionable errors: ChromeAppleScriptDisabledError, ChromeAutomationNotAuthorizedError (Apple event -1743), ChromeNoSlackTabError, and ChromeAppBoundEncryptionError for Chrome 127+ v20 values that cannot be decrypted outside Chrome.
  • src/cli/auth-command.ts: import-chrome now prints the workspace URLs it keyed tokens to. Tokens are stored per workspace URL, and on Enterprise Grid an entry keyed to the org shell (https://<org>.enterprise.slack.com) cannot serve workspace-scoped calls, which was previously invisible without a separate auth whoami.
  • src/cli/context-client-resolver.ts: the implicit browser fallback swallows the new Chrome errors. They are actionable only for an explicit auth import-chrome, not for every read command that happens to fall through to browser extraction.
  • README.md: document the Automation consent and Safe Storage keychain prerequisites, and the Enterprise Grid workspace-URL guidance.

Verification

  • bun test — 410 pass, 0 fail. New test/chrome-auth.test.ts covers team parsing (including the no-tab sentinel and the xoxc/URL filter), v10 Safe Storage decryption, percent-decoding, the v20 App-Bound Encryption error, wrong-password and empty-value handling, and profile/cookie-path discovery.
  • bun run typecheck, bun run lint, bun run format:check — clean.
  • Confirmed against a live Chrome profile that the d cookie is is_httponly=1 and stored as a v10 value, i.e. unreachable via document.cookie and reachable via the cookie store.

Risks

  • Reading the cookie store needs access to the Chrome Safe Storage keychain item, so the first run prompts for keychain approval. Previously import-chrome never reached a keychain prompt because it failed earlier.
  • Chrome profiles whose cookies use App-Bound Encryption (v20) still cannot be imported. That is now an explicit error pointing at import-desktop / import-brave / import-firefox instead of a silent failure.
  • extractFromChrome() is now async and can throw instead of only returning null. Both call sites are updated; the opportunistic resolver path still degrades quietly.

import-chrome read the d cookie with document.cookie through AppleScript, but
Slack sets that cookie HttpOnly, so the page context never sees it. Extraction
failed on the first check and every failure collapsed into one message:
"Could not extract tokens from Chrome."

Read the cookie from Chrome's cookie store and decrypt it with the Chrome Safe
Storage keychain password, matching the Brave and Slack-desktop paths, and
surface the setup failures that used to be swallowed: Apple Events disabled,
missing Automation consent, no Slack tab, and App-Bound Encryption (v20).
import-chrome now also prints the workspace URLs it keyed tokens to, because a
token stored against an Enterprise Grid org shell cannot serve workspace calls.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-Authored-By: Paperclip <noreply@paperclip.ing>
@arnaud-gp
arnaud-gp force-pushed the fix/chrome-import-httponly-cookie branch from f9fbdbe to 02a116a Compare September 20, 2026 12:25
@arnaud-gp arnaud-gp closed this Sep 20, 2026
@arnaud-gp
arnaud-gp deleted the fix/chrome-import-httponly-cookie branch September 20, 2026 13:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant