Slack's xoxc- session tokens require an HttpOnly d cookie that JavaScript can't read. But you don't need to extract it. By running fetch() inside Chrome's Slack tab via AppleScript, the browser attaches the cookie automatically.
No bots, no webhooks, no OAuth apps. Just your existing Slack session.
- macOS (uses
osascript) - Chrome with a
app.slack.comtab open - Chrome > View > Developer > Allow JavaScript from Apple Events
slack_post() {
local channel="$1" msg="$2"
local b64=$(printf '%s' "$msg" | base64)
osascript <<EOF
tell application "Google Chrome"
repeat with w from 1 to count of windows
repeat with t from 1 to count of tabs of window w
if URL of tab t of window w starts with "https://app.slack.com" then
tell tab t of window w
execute javascript "
window.__slackResult = null;
(async () => {
const cfg = JSON.parse(localStorage.getItem('localConfig_v2'));
const team = Object.values(cfg.teams).find(t =>
t.name === 'YOUR_WORKSPACE_NAME'
);
const body = new URLSearchParams({
token: team.token,
channel: '$channel',
text: atob('$b64')
});
const r = await fetch('/api/chat.postMessage', {
method: 'POST', credentials: 'include',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: body.toString()
});
window.__slackResult = JSON.stringify(await r.json());
})();
"
delay 3
return execute javascript "window.__slackResult"
end tell
end if
end repeat
end repeat
return "ERROR: No Slack tab found in Chrome"
end tell
EOF
}slack_post "C047F6T8Z7Z" "Hello from the terminal!"- AppleScript finds the first Chrome tab on
app.slack.com - It injects JavaScript that reads the workspace token from
localStorage fetch('/api/chat.postMessage', { credentials: 'include' })makes a same-origin API call; the browser attaches the HttpOnlydsession cookie automatically- The message is base64-encoded in bash and decoded with
atob()in JS to avoid quoting issues between bash, AppleScript, and JavaScript - The result JSON is returned to the shell
- Replace
YOUR_WORKSPACE_NAMEwith your Slack workspace name, or remove the.find()filter if you only have one workspace - The
delay 3gives the async fetch time to complete before reading the result - Works for any Slack API method, not just
chat.postMessage - Same technique used by tools that extract JWTs from browser localStorage (e.g. for internal admin dashboards)