Skip to content

Fix empty auth token on all update subcommands - #8

Merged
edumansky merged 2 commits into
mainfrom
fix/update-tokens
Aug 19, 2026
Merged

Fix empty auth token on all update subcommands#8
edumansky merged 2 commits into
mainfrom
fix/update-tokens

Conversation

@edumansky

@edumansky edumansky commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Problem

Every update subcommand in the CLI sends an empty bearer token and fails with a 401:

$ webex calling workspaces update --workspace-id "$id" --body-file body.json --debug
DEBUG: PUT https://webexapis.com/v1/workspaces/$id
DEBUG: Response 401 (269 bytes)
Error: API error 401: {"message":"The request requires a valid access token set in
the Authorization request header.", ...}

The token is fine — the same token, URL, and body succeed via curl. The request goes
out as Authorization: Bearer with nothing after it.

skipAuth() in cmd/root.go decides which commands may run unauthenticated by matching
the bare command name against a reserved list, but it checked every command in the
chain, at any depth
:

for c := cmd; c != nil; c = c.Parent() {
    switch c.Name() {
    case "login", "logout", "auth", "config", "version", "update", ...

webex calling workspaces update ends in update, which collides with the top-level
self-update command webex update. PersistentPreRunE therefore returned early before
reaching config.SetToken(...), and the request was built with no credentials.

Affected: all 38 update subcommands across calling, cc, device, meetings,
messaging, and admin, plus webex cc agents login and webex cc agents logout
(same collision, against top-level login/logout). Present since the initial commit;
not a regression.

create and delete were never affected — neither name collides — which is why reads
and creates worked and made this look like a scope problem.

Two things hid the cause: --debug redacts the Authorization header, so the empty
value was invisible in exactly the output used to debug it, and a 401 reads as a
token/scope failure rather than a routing bug.

Fix

  • skipAuth() now resolves the top-level ancestor and matches only on that name, so a
    nested API subcommand named update no longer inherits the exemption. auth set-org
    keeps its existing carve-out.
  • Also exempt completion and cobra's hidden __complete/__completeNoDesc, which had
    the inverse bug — they demanded a token they never use, so shell completion failed for
    unauthenticated users.
  • --debug (and --dry-run) now print the Authorization header as
    Bearer <106 chars> instead of omitting it. Hiding the header entirely is what made
    this bug invisible: an empty token rendered identically to a valid one. The empty case
    now reads Bearer <0 chars>. No credential material is printed.
  • New webex auth token, which prints the resolved access token, refreshing it first if
    expired. This is what made the diagnosis possible (it enables reproducing any CLI call
    with curl), and it is carved out of skipAuth alongside set-org since it needs the
    token resolved. Happy to split this into its own PR if you'd rather keep the fix alone.

Verification

Against a live org, using the built binary:

Verb Before After
workspaces create 201 201
workspaces update 401 200
workspaces delete 204 204
workspaces list / get 200 200

Full create → update → delete lifecycle passes, and all test resources were cleaned up.
Commands that must not require auth (version, config get, completion, --help)
still run without a token; auth status and the read paths still resolve one.
go build and go vet ./... are clean.

cc agents login / logout are fixed by the same change but were verified by reading
the code only — exercising them changes live agent state.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KJEaYFr7zMmqbF6j1mZFT3

edumansky and others added 2 commits August 19, 2026 13:18
--debug omitted the Authorization header entirely, so a request sent with an
empty bearer token looked identical to a correctly authenticated one. Print the
scheme and credential length instead of hiding the header.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KJEaYFr7zMmqbF6j1mZFT3
@edumansky
edumansky merged commit b965a9c into main Aug 19, 2026
2 checks passed
@edumansky
edumansky deleted the fix/update-tokens branch August 19, 2026 19:24
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