agent-messenger 2.1.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/.env.template +35 -17
- package/README.md +7 -7
- package/bun.lock +31 -7
- package/dist/package.json +5 -3
- package/dist/src/platforms/channeltalk/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/channeltalk/commands/auth.js +35 -28
- package/dist/src/platforms/channeltalk/commands/auth.js.map +1 -1
- package/dist/src/platforms/channeltalk/ensure-auth.js +6 -6
- package/dist/src/platforms/channeltalk/ensure-auth.js.map +1 -1
- package/dist/src/platforms/channeltalk/token-extractor.d.ts +23 -1
- package/dist/src/platforms/channeltalk/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/channeltalk/token-extractor.js +299 -29
- package/dist/src/platforms/channeltalk/token-extractor.js.map +1 -1
- package/dist/src/platforms/discord/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/auth.js +57 -49
- package/dist/src/platforms/discord/commands/auth.js.map +1 -1
- package/dist/src/platforms/discord/ensure-auth.js +3 -3
- package/dist/src/platforms/discord/ensure-auth.js.map +1 -1
- package/dist/src/platforms/discord/token-extractor.d.ts +6 -1
- package/dist/src/platforms/discord/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/discord/token-extractor.js +167 -14
- package/dist/src/platforms/discord/token-extractor.js.map +1 -1
- package/dist/src/platforms/instagram/client.d.ts +2 -0
- package/dist/src/platforms/instagram/client.d.ts.map +1 -1
- package/dist/src/platforms/instagram/client.js +2 -2
- package/dist/src/platforms/instagram/client.js.map +1 -1
- package/dist/src/platforms/instagram/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/instagram/commands/auth.js +107 -14
- package/dist/src/platforms/instagram/commands/auth.js.map +1 -1
- package/dist/src/platforms/instagram/ensure-auth.d.ts.map +1 -1
- package/dist/src/platforms/instagram/ensure-auth.js +57 -11
- package/dist/src/platforms/instagram/ensure-auth.js.map +1 -1
- package/dist/src/platforms/instagram/index.d.ts +1 -0
- package/dist/src/platforms/instagram/index.d.ts.map +1 -1
- package/dist/src/platforms/instagram/index.js +1 -0
- package/dist/src/platforms/instagram/index.js.map +1 -1
- package/dist/src/platforms/instagram/token-extractor.d.ts +44 -0
- package/dist/src/platforms/instagram/token-extractor.d.ts.map +1 -0
- package/dist/src/platforms/instagram/token-extractor.js +407 -0
- package/dist/src/platforms/instagram/token-extractor.js.map +1 -0
- package/dist/src/platforms/kakaotalk/client.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/client.js +2 -1
- package/dist/src/platforms/kakaotalk/client.js.map +1 -1
- package/dist/src/platforms/kakaotalk/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/commands/auth.js +14 -13
- package/dist/src/platforms/kakaotalk/commands/auth.js.map +1 -1
- package/dist/src/platforms/kakaotalk/protocol/connection.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/protocol/connection.js +2 -1
- package/dist/src/platforms/kakaotalk/protocol/connection.js.map +1 -1
- package/dist/src/platforms/line/client.d.ts.map +1 -1
- package/dist/src/platforms/line/client.js +36 -9
- package/dist/src/platforms/line/client.js.map +1 -1
- package/dist/src/platforms/line/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/line/commands/auth.js +6 -5
- package/dist/src/platforms/line/commands/auth.js.map +1 -1
- package/dist/src/platforms/slack/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/auth.js +11 -10
- package/dist/src/platforms/slack/commands/auth.js.map +1 -1
- package/dist/src/platforms/slack/token-extractor.d.ts +9 -0
- package/dist/src/platforms/slack/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/slack/token-extractor.js +300 -23
- package/dist/src/platforms/slack/token-extractor.js.map +1 -1
- package/dist/src/platforms/teams/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/teams/commands/auth.js +9 -8
- package/dist/src/platforms/teams/commands/auth.js.map +1 -1
- package/dist/src/platforms/teams/ensure-auth.d.ts.map +1 -1
- package/dist/src/platforms/teams/ensure-auth.js +2 -1
- package/dist/src/platforms/teams/ensure-auth.js.map +1 -1
- package/dist/src/platforms/teams/token-extractor.d.ts +5 -0
- package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/teams/token-extractor.js +161 -29
- package/dist/src/platforms/teams/token-extractor.js.map +1 -1
- package/dist/src/platforms/telegram/client.d.ts.map +1 -1
- package/dist/src/platforms/telegram/client.js +25 -7
- package/dist/src/platforms/telegram/client.js.map +1 -1
- package/dist/src/platforms/telegram/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/telegram/commands/auth.js +6 -5
- package/dist/src/platforms/telegram/commands/auth.js.map +1 -1
- package/dist/src/platforms/webex/client.d.ts +12 -0
- package/dist/src/platforms/webex/client.d.ts.map +1 -1
- package/dist/src/platforms/webex/client.js +168 -1
- package/dist/src/platforms/webex/client.js.map +1 -1
- package/dist/src/platforms/webex/commands/auth.d.ts +4 -0
- package/dist/src/platforms/webex/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/webex/commands/auth.js +50 -4
- package/dist/src/platforms/webex/commands/auth.js.map +1 -1
- package/dist/src/platforms/webex/credential-manager.js +1 -1
- package/dist/src/platforms/webex/credential-manager.js.map +1 -1
- package/dist/src/platforms/webex/encryption.d.ts +10 -0
- package/dist/src/platforms/webex/encryption.d.ts.map +1 -0
- package/dist/src/platforms/webex/encryption.js +49 -0
- package/dist/src/platforms/webex/encryption.js.map +1 -0
- package/dist/src/platforms/webex/ensure-auth.d.ts.map +1 -1
- package/dist/src/platforms/webex/ensure-auth.js +25 -5
- package/dist/src/platforms/webex/ensure-auth.js.map +1 -1
- package/dist/src/platforms/webex/index.d.ts +2 -0
- package/dist/src/platforms/webex/index.d.ts.map +1 -1
- package/dist/src/platforms/webex/index.js +1 -0
- package/dist/src/platforms/webex/index.js.map +1 -1
- package/dist/src/platforms/webex/token-extractor.d.ts +29 -0
- package/dist/src/platforms/webex/token-extractor.d.ts.map +1 -0
- package/dist/src/platforms/webex/token-extractor.js +393 -0
- package/dist/src/platforms/webex/token-extractor.js.map +1 -0
- package/dist/src/platforms/webex/types.d.ts +8 -1
- package/dist/src/platforms/webex/types.d.ts.map +1 -1
- package/dist/src/platforms/webex/types.js +4 -1
- package/dist/src/platforms/webex/types.js.map +1 -1
- package/dist/src/platforms/whatsapp/client.d.ts.map +1 -1
- package/dist/src/platforms/whatsapp/client.js +6 -2
- package/dist/src/platforms/whatsapp/client.js.map +1 -1
- package/dist/src/shared/utils/derived-key-cache.d.ts +1 -1
- package/dist/src/shared/utils/derived-key-cache.d.ts.map +1 -1
- package/dist/src/shared/utils/error-handler.d.ts +1 -1
- package/dist/src/shared/utils/error-handler.d.ts.map +1 -1
- package/dist/src/shared/utils/error-handler.js +3 -2
- package/dist/src/shared/utils/error-handler.js.map +1 -1
- package/dist/src/shared/utils/stderr.d.ts +5 -0
- package/dist/src/shared/utils/stderr.d.ts.map +1 -0
- package/dist/src/shared/utils/stderr.js +18 -0
- package/dist/src/shared/utils/stderr.js.map +1 -0
- package/docs/content/docs/cli/channeltalk.mdx +7 -7
- package/docs/content/docs/cli/discord.mdx +3 -3
- package/docs/content/docs/cli/instagram.mdx +28 -6
- package/docs/content/docs/cli/slack.mdx +2 -2
- package/docs/content/docs/cli/teams.mdx +6 -4
- package/docs/content/docs/cli/webex.mdx +32 -11
- package/e2e/README.md +132 -8
- package/e2e/channeltalk.e2e.test.ts +2 -7
- package/e2e/channeltalkbot.e2e.test.ts +2 -6
- package/e2e/config.ts +172 -10
- package/e2e/helpers.ts +7 -0
- package/e2e/instagram.e2e.test.ts +97 -0
- package/e2e/kakaotalk.e2e.test.ts +74 -0
- package/e2e/line.e2e.test.ts +92 -0
- package/e2e/teams.e2e.test.ts +46 -1
- package/e2e/telegram.e2e.test.ts +84 -0
- package/e2e/webex.e2e.test.ts +190 -0
- package/e2e/whatsapp.e2e.test.ts +90 -0
- package/e2e/whatsappbot.e2e.test.ts +78 -0
- package/package.json +5 -3
- package/skills/agent-channeltalk/SKILL.md +9 -9
- package/skills/agent-channeltalk/references/authentication.md +21 -18
- package/skills/agent-channeltalkbot/SKILL.md +1 -1
- package/skills/agent-discord/SKILL.md +5 -5
- package/skills/agent-discord/references/authentication.md +8 -8
- package/skills/agent-discordbot/SKILL.md +1 -1
- package/skills/agent-instagram/SKILL.md +51 -9
- package/skills/agent-instagram/references/authentication.md +35 -3
- package/skills/agent-kakaotalk/SKILL.md +1 -1
- package/skills/agent-line/SKILL.md +1 -1
- package/skills/agent-slack/SKILL.md +5 -5
- package/skills/agent-slack/references/authentication.md +8 -8
- package/skills/agent-slackbot/SKILL.md +1 -1
- package/skills/agent-teams/SKILL.md +6 -6
- package/skills/agent-teams/references/authentication.md +8 -8
- package/skills/agent-telegram/SKILL.md +1 -1
- package/skills/agent-webex/SKILL.md +35 -15
- package/skills/agent-webex/references/authentication.md +63 -9
- package/skills/agent-webex/references/common-patterns.md +6 -3
- package/skills/agent-whatsapp/SKILL.md +1 -1
- package/skills/agent-whatsappbot/SKILL.md +1 -1
- package/src/platforms/channeltalk/commands/auth.test.ts +5 -5
- package/src/platforms/channeltalk/commands/auth.ts +38 -32
- package/src/platforms/channeltalk/ensure-auth.test.ts +6 -6
- package/src/platforms/channeltalk/ensure-auth.ts +6 -6
- package/src/platforms/channeltalk/token-extractor.test.ts +182 -15
- package/src/platforms/channeltalk/token-extractor.ts +344 -30
- package/src/platforms/discord/commands/auth.test.ts +3 -3
- package/src/platforms/discord/commands/auth.ts +58 -54
- package/src/platforms/discord/ensure-auth.test.ts +3 -3
- package/src/platforms/discord/ensure-auth.ts +3 -3
- package/src/platforms/discord/token-extractor.test.ts +199 -27
- package/src/platforms/discord/token-extractor.ts +190 -17
- package/src/platforms/instagram/client.ts +2 -2
- package/src/platforms/instagram/commands/auth.ts +133 -14
- package/src/platforms/instagram/ensure-auth.ts +63 -12
- package/src/platforms/instagram/index.ts +1 -0
- package/src/platforms/instagram/token-extractor.test.ts +424 -0
- package/src/platforms/instagram/token-extractor.ts +478 -0
- package/src/platforms/kakaotalk/client.ts +3 -1
- package/src/platforms/kakaotalk/commands/auth.ts +14 -13
- package/src/platforms/kakaotalk/protocol/connection.ts +3 -1
- package/src/platforms/line/client.ts +39 -14
- package/src/platforms/line/commands/auth.ts +7 -6
- package/src/platforms/slack/cli.test.ts +6 -5
- package/src/platforms/slack/commands/auth.test.ts +11 -7
- package/src/platforms/slack/commands/auth.ts +11 -10
- package/src/platforms/slack/token-extractor.test.ts +98 -1
- package/src/platforms/slack/token-extractor.ts +338 -26
- package/src/platforms/teams/commands/auth.ts +9 -8
- package/src/platforms/teams/ensure-auth.ts +3 -1
- package/src/platforms/teams/token-extractor.test.ts +136 -17
- package/src/platforms/teams/token-extractor.ts +182 -31
- package/src/platforms/telegram/client.test.ts +134 -0
- package/src/platforms/telegram/client.ts +27 -6
- package/src/platforms/telegram/commands/auth.ts +6 -5
- package/src/platforms/webex/client.test.ts +314 -0
- package/src/platforms/webex/client.ts +231 -1
- package/src/platforms/webex/commands/auth.ts +71 -4
- package/src/platforms/webex/commands/member.test.ts +10 -1
- package/src/platforms/webex/commands/message.test.ts +9 -5
- package/src/platforms/webex/commands/snapshot.test.ts +13 -4
- package/src/platforms/webex/commands/space.test.ts +12 -2
- package/src/platforms/webex/credential-manager.ts +1 -1
- package/src/platforms/webex/encryption.ts +53 -0
- package/src/platforms/webex/ensure-auth.test.ts +4 -0
- package/src/platforms/webex/ensure-auth.ts +27 -4
- package/src/platforms/webex/index.ts +2 -0
- package/src/platforms/webex/token-extractor.test.ts +327 -0
- package/src/platforms/webex/token-extractor.ts +460 -0
- package/src/platforms/webex/types.ts +8 -2
- package/src/platforms/webex/typings/node-jose.d.ts +27 -0
- package/src/platforms/whatsapp/client.ts +11 -7
- package/src/shared/utils/derived-key-cache.ts +1 -1
- package/src/shared/utils/error-handler.ts +4 -2
- package/src/shared/utils/stderr.ts +22 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: agent-webex
|
|
3
3
|
description: Interact with Cisco Webex - send messages, read spaces, manage memberships
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.3.0
|
|
5
5
|
allowed-tools: Bash(agent-webex:*)
|
|
6
6
|
metadata:
|
|
7
7
|
openclaw:
|
|
@@ -16,12 +16,15 @@ metadata:
|
|
|
16
16
|
|
|
17
17
|
# Agent Webex
|
|
18
18
|
|
|
19
|
-
A TypeScript CLI tool that enables AI agents and humans to interact with Cisco Webex through a simple command interface.
|
|
19
|
+
A TypeScript CLI tool that enables AI agents and humans to interact with Cisco Webex through a simple command interface. Supports browser token extraction (zero-config, sends as you) and OAuth Device Grant flow.
|
|
20
20
|
|
|
21
21
|
## Quick Start
|
|
22
22
|
|
|
23
23
|
```bash
|
|
24
|
-
#
|
|
24
|
+
# Extract token from browser (Chrome, Edge, Arc, Brave) — messages appear as you
|
|
25
|
+
agent-webex auth extract
|
|
26
|
+
|
|
27
|
+
# Or: Log in via OAuth Device Grant (opens browser, messages show "via agent-messenger")
|
|
25
28
|
agent-webex auth login
|
|
26
29
|
|
|
27
30
|
# Get workspace snapshot
|
|
@@ -36,10 +39,35 @@ agent-webex space list
|
|
|
36
39
|
|
|
37
40
|
## Authentication
|
|
38
41
|
|
|
39
|
-
Webex
|
|
42
|
+
Webex supports two authentication methods:
|
|
43
|
+
|
|
44
|
+
1. **Browser token extraction** (recommended): Extracts your first-party token from a Chromium browser where you're logged into web.webex.com. Messages appear as you — no "via" label.
|
|
45
|
+
2. **OAuth Device Grant**: Opens a browser for you to authorize. Messages show "via agent-messenger" label.
|
|
46
|
+
|
|
47
|
+
### Browser Token Extraction (Recommended)
|
|
48
|
+
|
|
49
|
+
`agent-webex auth extract` reads your Webex session token from Chrome, Edge, Arc, or Brave. You must be logged into web.webex.com in one of these browsers. No configuration needed.
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Extract token from browser — messages appear as you
|
|
53
|
+
agent-webex auth extract
|
|
54
|
+
|
|
55
|
+
# With debug output
|
|
56
|
+
agent-webex auth extract --debug
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Supported browsers**: Chrome, Chrome Canary, Edge, Arc, Brave, Vivaldi, Chromium
|
|
60
|
+
|
|
61
|
+
**How it works**: The Webex web client stores its authentication token in the browser's localStorage. This CLI reads it directly from the browser's LevelDB files — no browser automation, no password prompts. The token is stored locally in `~/.config/agent-messenger/`.
|
|
62
|
+
|
|
63
|
+
**When to re-extract**: Browser tokens expire. When your token expires, re-run `agent-webex auth extract` or let auto-extraction handle it (the CLI attempts extraction automatically on each run).
|
|
64
|
+
|
|
65
|
+
### OAuth Device Grant (Fallback)
|
|
40
66
|
|
|
41
67
|
`agent-webex auth login` starts the Device Grant flow: it displays a verification URL and user code, then opens the browser. You enter the code at the verification page and approve access. The CLI polls for the token automatically. Access and refresh tokens are stored locally, and the access token auto-refreshes via the refresh token.
|
|
42
68
|
|
|
69
|
+
Note: Messages sent via OAuth Device Grant show "via agent-messenger" because the token is associated with a third-party Webex Integration.
|
|
70
|
+
|
|
43
71
|
Optionally, pass `--token <bot-token>` for bot token auth. Or pass `--client-id <id> --client-secret <secret>` to use your own Webex Integration credentials instead of the built-in ones.
|
|
44
72
|
|
|
45
73
|
Env vars `AGENT_WEBEX_CLIENT_ID` / `AGENT_WEBEX_CLIENT_SECRET` can also override the built-in credentials.
|
|
@@ -61,22 +89,14 @@ agent-webex auth status
|
|
|
61
89
|
agent-webex auth logout
|
|
62
90
|
```
|
|
63
91
|
|
|
64
|
-
### How Login Works
|
|
65
|
-
|
|
66
|
-
1. Run `agent-webex auth login`
|
|
67
|
-
2. CLI requests a device code from Webex
|
|
68
|
-
3. Browser opens to Webex verification page
|
|
69
|
-
4. Enter the displayed code and sign in
|
|
70
|
-
5. CLI automatically detects approval and stores tokens
|
|
71
|
-
6. Access token auto-refreshes via refresh token
|
|
72
|
-
|
|
73
92
|
### Token Types
|
|
74
93
|
|
|
75
|
-
- **
|
|
94
|
+
- **Extracted (browser)**: First-party token from web.webex.com. Messages appear as you. Requires re-extraction when expired.
|
|
95
|
+
- **OAuth Device Grant**: Zero-config login. Access token auto-refreshes. Messages show "via agent-messenger".
|
|
76
96
|
- **Bot Token**: Pass via `--token` flag. Never expires. Best for CI/CD.
|
|
77
97
|
- **Custom Integration**: Pass `--client-id` + `--client-secret` or set env vars for your own Webex Integration.
|
|
78
98
|
|
|
79
|
-
**IMPORTANT**: NEVER guide the user to open a web browser, use DevTools, or manually copy tokens from a browser's network inspector. Always use `agent-webex auth login` for
|
|
99
|
+
**IMPORTANT**: NEVER guide the user to open a web browser, use DevTools, or manually copy tokens from a browser's network inspector. Always use `agent-webex auth extract` or `agent-webex auth login` for authentication.
|
|
80
100
|
|
|
81
101
|
For detailed token management, see [references/authentication.md](references/authentication.md).
|
|
82
102
|
|
|
@@ -2,17 +2,41 @@
|
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
|
-
agent-webex supports
|
|
5
|
+
agent-webex supports four authentication methods against the Webex REST API (`https://webexapis.com/v1`):
|
|
6
6
|
|
|
7
|
-
1. **
|
|
8
|
-
2. **
|
|
9
|
-
3. **
|
|
7
|
+
1. **Browser Token Extraction**: Extracts your first-party token and cached encryption keys from a Chromium browser where you're logged into web.webex.com. Supports all operations including encrypted messaging via the internal API. Zero-config.
|
|
8
|
+
2. **OAuth Device Grant** (recommended for messaging): Zero-config. Run `auth login`, approve in browser, done. Tokens refresh automatically. Supports all operations including sending messages (shows "via agent-messenger").
|
|
9
|
+
3. **Bot Token**: Pass via `auth login --token`. Never expires. Best for CI/CD.
|
|
10
|
+
4. **Personal Access Token (PAT)**: Pass via `auth login --token`. Expires in 12 hours. For quick testing.
|
|
10
11
|
|
|
11
12
|
## Token Types
|
|
12
13
|
|
|
13
|
-
###
|
|
14
|
+
### Browser Token Extraction
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
Extracts your first-party Webex session token from a Chromium-based browser where you're logged into web.webex.com. Supports full messaging with end-to-end encryption. The extracted token uses Webex's internal conversation API for sending messages. Encryption keys are also extracted from the browser's cached KMS key store, enabling client-side JWE encryption so messages appear as encrypted in the Webex client.
|
|
17
|
+
|
|
18
|
+
- **How it works**: Run `agent-webex auth extract`. The CLI scans Chromium browser profiles for Webex localStorage data (LevelDB files). It finds the `webex-storage` key containing `Credentials.@.supertoken` and extracts the access token. It also extracts `userId` from the Device namespace and cached KMS encryption keys from the unbounded storage — these keys enable end-to-end encrypted messaging via the internal API. No browser automation, no password prompts.
|
|
19
|
+
- **Supported browsers**: Chrome, Chrome Canary, Edge, Arc, Brave, Vivaldi, Chromium
|
|
20
|
+
- **Token lifetime**: Depends on Webex session policy (typically hours to days). Re-extract when expired.
|
|
21
|
+
- **Auto-extraction**: The CLI attempts browser extraction automatically when no valid token is stored, so you often don't need to run `auth extract` manually.
|
|
22
|
+
- **End-to-end encryption**: When encryption keys are found in the browser's cache, messages are encrypted client-side (JWE with AES-256-GCM) before sending via the internal conversation API. This ensures messages appear as encrypted in the Webex client. If no keys are found (e.g., the conversation hasn't been opened in the browser), messages fall back to plaintext.
|
|
23
|
+
- **Best for**: Interactive use, sending messages as yourself without the "via" label
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Extract token from browser
|
|
27
|
+
agent-webex auth extract
|
|
28
|
+
|
|
29
|
+
# With debug output
|
|
30
|
+
agent-webex auth extract --debug
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Requirements**: You must be logged into web.webex.com in a supported Chromium browser. The browser does not need to be running — the CLI reads directly from on-disk LevelDB files.
|
|
34
|
+
|
|
35
|
+
**Limitations**: Direct messages (`message dm`) require an existing conversation with the recipient. The extracted token cannot create new 1:1 conversations — start one from the Webex app first, then use the CLI.
|
|
36
|
+
|
|
37
|
+
### OAuth Device Grant
|
|
38
|
+
|
|
39
|
+
The fallback authentication method when browser extraction is unavailable. No credentials to copy, no developer portal setup required.
|
|
16
40
|
|
|
17
41
|
- **How it works**: Run `agent-webex auth login`. The CLI requests a device code from Webex, opens your browser, and waits for you to approve. Once approved, access and refresh tokens are stored automatically.
|
|
18
42
|
- **Access token lifetime**: 14 days
|
|
@@ -56,7 +80,10 @@ agent-webex auth login --token "YOUR_PAT_HERE"
|
|
|
56
80
|
## Logging In
|
|
57
81
|
|
|
58
82
|
```bash
|
|
59
|
-
#
|
|
83
|
+
# Browser extraction (recommended — messages appear as you)
|
|
84
|
+
agent-webex auth extract
|
|
85
|
+
|
|
86
|
+
# Device Grant (fallback — messages show "via agent-messenger")
|
|
60
87
|
agent-webex auth login
|
|
61
88
|
|
|
62
89
|
# With custom Integration credentials
|
|
@@ -69,6 +96,8 @@ agent-webex auth login --token <bot-token>
|
|
|
69
96
|
agent-webex auth login --token <pat>
|
|
70
97
|
```
|
|
71
98
|
|
|
99
|
+
When using `auth extract`, the CLI reads your Webex session from the browser's LevelDB storage. No prompts, no browser automation.
|
|
100
|
+
|
|
72
101
|
When using `--token`, the CLI validates the token against the Webex API before saving. If validation fails, you'll see an error and the token won't be stored.
|
|
73
102
|
|
|
74
103
|
When using Device Grant, the CLI prints a URL and code, opens your browser, then polls until you approve (or the code expires).
|
|
@@ -118,6 +147,17 @@ This removes the stored credentials from disk.
|
|
|
118
147
|
|
|
119
148
|
### Format
|
|
120
149
|
|
|
150
|
+
Extracted credentials (from `auth extract`):
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"accessToken": "...",
|
|
155
|
+
"refreshToken": "...",
|
|
156
|
+
"expiresAt": 1234567890,
|
|
157
|
+
"tokenType": "extracted"
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
121
161
|
OAuth credentials (from Device Grant):
|
|
122
162
|
|
|
123
163
|
```json
|
|
@@ -155,6 +195,19 @@ Manual credentials (from `--token`):
|
|
|
155
195
|
|
|
156
196
|
## Token Lifecycle
|
|
157
197
|
|
|
198
|
+
### Browser Token Extraction
|
|
199
|
+
|
|
200
|
+
```
|
|
201
|
+
auth extract -> Scan browser LevelDB -> Extract supertoken -> Access token (session-based)
|
|
202
|
+
|
|
|
203
|
+
Token expires
|
|
204
|
+
|
|
|
205
|
+
Re-run "auth extract"
|
|
206
|
+
(or auto-extraction on next CLI run)
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Browser-extracted tokens have no refresh mechanism — when they expire, re-extract from the browser (where your active session keeps them fresh). The CLI attempts auto-extraction on each run, so manual re-extraction is rarely needed.
|
|
210
|
+
|
|
158
211
|
### OAuth Device Grant
|
|
159
212
|
|
|
160
213
|
```
|
|
@@ -274,8 +327,9 @@ With a valid token, agent-webex has the same permissions as the token owner:
|
|
|
274
327
|
|
|
275
328
|
### Best Practices
|
|
276
329
|
|
|
277
|
-
1. **Use
|
|
278
|
-
2. **Use
|
|
330
|
+
1. **Use browser extraction for interactive work**: Zero-config, messages appear as you, no "via" label
|
|
331
|
+
2. **Use Device Grant as fallback**: When browser extraction isn't available (no Chromium browser, headless server)
|
|
332
|
+
3. **Use bot tokens for automation**: They don't expire and have scoped access
|
|
279
333
|
3. **Protect credentials.json**: Never commit to version control
|
|
280
334
|
4. **Rotate PATs regularly**: Don't reuse expired tokens. Generate fresh ones
|
|
281
335
|
5. **Revoke compromised tokens**: Regenerate bot tokens at https://developer.webex.com/my-apps if compromised
|
|
@@ -8,14 +8,17 @@ This guide covers typical workflows for AI agents interacting with Cisco Webex u
|
|
|
8
8
|
|
|
9
9
|
## Auth Patterns
|
|
10
10
|
|
|
11
|
-
### Pattern 1:
|
|
11
|
+
### Pattern 1: Authenticate
|
|
12
12
|
|
|
13
13
|
**Use case**: First-time setup or token renewal
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
16
|
#!/bin/bash
|
|
17
17
|
|
|
18
|
-
#
|
|
18
|
+
# Recommended: Browser extraction (zero-config, sends as you, no "via" label)
|
|
19
|
+
agent-webex auth extract
|
|
20
|
+
|
|
21
|
+
# Fallback: Device Grant (zero-config, opens browser, shows "via agent-messenger")
|
|
19
22
|
agent-webex auth login
|
|
20
23
|
|
|
21
24
|
# With a bot token (never expires, for CI/CD)
|
|
@@ -25,7 +28,7 @@ agent-webex auth login --token "YOUR_BOT_TOKEN_HERE"
|
|
|
25
28
|
agent-webex auth login --token "YOUR_PAT_HERE"
|
|
26
29
|
```
|
|
27
30
|
|
|
28
|
-
**When to use**: Before any other command, if not already authenticated.
|
|
31
|
+
**When to use**: Before any other command, if not already authenticated. Browser extraction is preferred — it auto-runs when no valid token is stored. It also extracts cached KMS encryption keys from the browser, enabling end-to-end encrypted messaging via the internal API.
|
|
29
32
|
|
|
30
33
|
### Pattern 2: Check Auth Status
|
|
31
34
|
|
|
@@ -19,8 +19,8 @@ const mockListChannels = mock(() =>
|
|
|
19
19
|
{ id: 'ws-2', name: 'Workspace 2' },
|
|
20
20
|
]),
|
|
21
21
|
)
|
|
22
|
-
const mockExtract = mock
|
|
23
|
-
Promise.resolve({ accountCookie: 'fresh-account', sessionCookie: 'fresh-session' }),
|
|
22
|
+
const mockExtract = mock(() =>
|
|
23
|
+
Promise.resolve([{ accountCookie: 'fresh-account', sessionCookie: 'fresh-session' }]),
|
|
24
24
|
)
|
|
25
25
|
|
|
26
26
|
import {
|
|
@@ -113,7 +113,7 @@ describe('channel auth commands', () => {
|
|
|
113
113
|
{ id: 'ws-2', name: 'Workspace 2' },
|
|
114
114
|
]),
|
|
115
115
|
)
|
|
116
|
-
mockExtract.mockImplementation(() => Promise.resolve({ accountCookie: 'fresh-account', sessionCookie: 'fresh-session' }))
|
|
116
|
+
mockExtract.mockImplementation(() => Promise.resolve([{ accountCookie: 'fresh-account', sessionCookie: 'fresh-session' }]))
|
|
117
117
|
})
|
|
118
118
|
|
|
119
119
|
describe('extractAction', () => {
|
|
@@ -177,7 +177,7 @@ describe('channel auth commands', () => {
|
|
|
177
177
|
})
|
|
178
178
|
|
|
179
179
|
test('returns error when token extraction fails', async () => {
|
|
180
|
-
mockExtract.mockImplementation(() => Promise.resolve(
|
|
180
|
+
mockExtract.mockImplementation(() => Promise.resolve([]))
|
|
181
181
|
|
|
182
182
|
const result = await extractAction()
|
|
183
183
|
|
|
@@ -192,7 +192,7 @@ describe('channel auth commands', () => {
|
|
|
192
192
|
const result = await extractAction()
|
|
193
193
|
|
|
194
194
|
expect(result).toEqual({
|
|
195
|
-
error: 'No
|
|
195
|
+
error: 'No valid credentials found. Make sure Channel Talk desktop app or browser is logged in.',
|
|
196
196
|
})
|
|
197
197
|
})
|
|
198
198
|
})
|
|
@@ -82,45 +82,51 @@ export async function extractAction(options: ActionOptions = {}): Promise<Extrac
|
|
|
82
82
|
const extractor = createTokenExtractor()
|
|
83
83
|
const extracted = await extractor.extract()
|
|
84
84
|
|
|
85
|
-
if (
|
|
85
|
+
if (extracted.length === 0) {
|
|
86
86
|
return {
|
|
87
87
|
error: 'No credentials. Make sure Channel Talk desktop app is installed and logged in.',
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
91
|
+
for (const cookies of extracted) {
|
|
92
|
+
try {
|
|
93
|
+
const client = await createChannelClient(cookies.accountCookie, cookies.sessionCookie)
|
|
94
|
+
const account = await client.getAccount()
|
|
95
|
+
const channels = await client.listChannels()
|
|
96
|
+
|
|
97
|
+
if (channels.length === 0) continue
|
|
98
|
+
|
|
99
|
+
const previousCurrent = await credManager.getCredentials()
|
|
100
|
+
|
|
101
|
+
for (const channel of channels) {
|
|
102
|
+
await credManager.setCredentials({
|
|
103
|
+
workspace_id: channel.id,
|
|
104
|
+
workspace_name: channel.name,
|
|
105
|
+
account_id: account.id,
|
|
106
|
+
account_name: account.name,
|
|
107
|
+
account_cookie: cookies.accountCookie,
|
|
108
|
+
session_cookie: cookies.sessionCookie,
|
|
109
|
+
})
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const previousStillExists = previousCurrent && channels.some((ch) => ch.id === previousCurrent.workspace_id)
|
|
113
|
+
const currentId = previousStillExists ? previousCurrent.workspace_id : channels[0].id
|
|
114
|
+
await credManager.setCurrent(currentId)
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
success: true,
|
|
118
|
+
workspaces: channels.map((ch) => ({
|
|
119
|
+
workspace_id: ch.id,
|
|
120
|
+
workspace_name: ch.name,
|
|
121
|
+
})),
|
|
122
|
+
current_workspace_id: currentId,
|
|
123
|
+
}
|
|
124
|
+
} catch {
|
|
125
|
+
continue
|
|
126
|
+
}
|
|
110
127
|
}
|
|
111
128
|
|
|
112
|
-
|
|
113
|
-
const currentId = previousStillExists ? previousCurrent.workspace_id : channels[0].id
|
|
114
|
-
await credManager.setCurrent(currentId)
|
|
115
|
-
|
|
116
|
-
return {
|
|
117
|
-
success: true,
|
|
118
|
-
workspaces: channels.map((ch) => ({
|
|
119
|
-
workspace_id: ch.id,
|
|
120
|
-
workspace_name: ch.name,
|
|
121
|
-
})),
|
|
122
|
-
current_workspace_id: currentId,
|
|
123
|
-
}
|
|
129
|
+
return { error: 'No valid credentials found. Make sure Channel Talk desktop app or browser is logged in.' }
|
|
124
130
|
} catch (error: unknown) {
|
|
125
131
|
return { error: (error as Error).message }
|
|
126
132
|
}
|
|
@@ -17,7 +17,7 @@ const mockGetCredentials = mock<() => Promise<
|
|
|
17
17
|
>>(() => Promise.resolve(null))
|
|
18
18
|
const mockSetCredentials = mock(() => Promise.resolve())
|
|
19
19
|
const mockSetCurrent = mock(() => Promise.resolve(true))
|
|
20
|
-
const mockExtract = mock(() => Promise.resolve(
|
|
20
|
+
const mockExtract = mock(() => Promise.resolve([]))
|
|
21
21
|
const mockGetAccount = mock(() => Promise.resolve({ id: 'acct-1', name: 'Alice' }))
|
|
22
22
|
const mockListChannels = mock(() => Promise.resolve([{ id: 'ws-1', name: 'Workspace 1' }]))
|
|
23
23
|
|
|
@@ -58,17 +58,17 @@ describe('ensureChannelAuth', () => {
|
|
|
58
58
|
mockGetCredentials.mockImplementation(() => Promise.resolve(null))
|
|
59
59
|
mockSetCredentials.mockImplementation(() => Promise.resolve())
|
|
60
60
|
mockSetCurrent.mockImplementation(() => Promise.resolve(true))
|
|
61
|
-
mockExtract.mockImplementation(() => Promise.resolve(
|
|
61
|
+
mockExtract.mockImplementation(() => Promise.resolve([]))
|
|
62
62
|
mockGetAccount.mockImplementation(() => Promise.resolve({ id: 'acct-1', name: 'Alice' }))
|
|
63
63
|
mockListChannels.mockImplementation(() => Promise.resolve([{ id: 'ws-1', name: 'Workspace 1' }]))
|
|
64
64
|
})
|
|
65
65
|
|
|
66
66
|
test('extracts and saves workspaces when no credentials exist', async () => {
|
|
67
67
|
mockExtract.mockImplementation(() =>
|
|
68
|
-
Promise.resolve({
|
|
68
|
+
Promise.resolve([{
|
|
69
69
|
accountCookie: 'account-cookie',
|
|
70
70
|
sessionCookie: 'session-cookie',
|
|
71
|
-
}),
|
|
71
|
+
}]),
|
|
72
72
|
)
|
|
73
73
|
mockListChannels.mockImplementation(() =>
|
|
74
74
|
Promise.resolve([
|
|
@@ -128,10 +128,10 @@ describe('ensureChannelAuth', () => {
|
|
|
128
128
|
)
|
|
129
129
|
mockGetAccount.mockImplementationOnce(() => Promise.reject(new Error('Unauthorized')))
|
|
130
130
|
mockExtract.mockImplementation(() =>
|
|
131
|
-
Promise.resolve({
|
|
131
|
+
Promise.resolve([{
|
|
132
132
|
accountCookie: 'fresh-account',
|
|
133
133
|
sessionCookie: 'fresh-session',
|
|
134
|
-
}),
|
|
134
|
+
}]),
|
|
135
135
|
)
|
|
136
136
|
|
|
137
137
|
await ensureChannelAuth()
|
|
@@ -58,11 +58,11 @@ export async function ensureChannelAuth(): Promise<void> {
|
|
|
58
58
|
|
|
59
59
|
const extractor = createTokenExtractor()
|
|
60
60
|
const extracted = await extractor.extract()
|
|
61
|
-
if (
|
|
61
|
+
if (extracted.length === 0) {
|
|
62
62
|
return
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
const client = await createChannelClient(extracted.accountCookie, extracted.sessionCookie)
|
|
65
|
+
const client = await createChannelClient(extracted[0].accountCookie, extracted[0].sessionCookie)
|
|
66
66
|
const account = await client.getAccount()
|
|
67
67
|
const channels = await client.listChannels()
|
|
68
68
|
if (channels.length === 0) {
|
|
@@ -76,8 +76,8 @@ export async function ensureChannelAuth(): Promise<void> {
|
|
|
76
76
|
workspace_name: currentChannel.name,
|
|
77
77
|
account_id: account.id,
|
|
78
78
|
account_name: account.name,
|
|
79
|
-
account_cookie: extracted.accountCookie,
|
|
80
|
-
session_cookie: extracted.sessionCookie,
|
|
79
|
+
account_cookie: extracted[0].accountCookie,
|
|
80
|
+
session_cookie: extracted[0].sessionCookie,
|
|
81
81
|
})
|
|
82
82
|
|
|
83
83
|
for (const channel of otherChannels) {
|
|
@@ -86,8 +86,8 @@ export async function ensureChannelAuth(): Promise<void> {
|
|
|
86
86
|
workspace_name: channel.name,
|
|
87
87
|
account_id: account.id,
|
|
88
88
|
account_name: account.name,
|
|
89
|
-
account_cookie: extracted.accountCookie,
|
|
90
|
-
session_cookie: extracted.sessionCookie,
|
|
89
|
+
account_cookie: extracted[0].accountCookie,
|
|
90
|
+
session_cookie: extracted[0].sessionCookie,
|
|
91
91
|
})
|
|
92
92
|
}
|
|
93
93
|
|