Skip to content

feat(tui,mcpdo): decode and show access-token claims - #2891

Merged
cliffhall merged 3 commits into
v2/mainfrom
v2/feat/2845-token-claims
Nov 5, 2026
Merged

cliffhall merged 3 commits into
v2/mainfrom
v2/feat/2845-token-claims

Conversation

@cliffhall

Copy link
Copy Markdown
Member

Closes #2845

What

Most OAuth failures against an MCP server — wrong audience, missing scope, expired token — are visible in the access token itself, but the TUI Auth tab and mcpdo showed it only as an opaque prefix. This decodes it, without verifying the signature (a viewer, not a validator).

  • core/auth/accessTokenClaims.ts (new, pure): summarizeAccessToken reads a JWT's iss, aud (string or list), sub, client_id (falling back to azp), scope (falling back to scp), iat and exp. For an opaque token it falls back to the scope / expires_in the token response carried. accessTokenDetailLines renders labelled rows with times relative to now ((in 34m), (expired 2m ago)), shared by both surfaces so they word things the same way. Claim strings have control characters stripped, because the authorization server mints them and they go to a terminal. A JWT-shaped token whose payload isn't a JSON object is treated as opaque.
  • TUI: a new Access Token Details section under OAuth Details on the Auth tab.
  • mcpdo: new auth/show <key> command. It takes the same key forms as auth/clear (store URL, exact store key, EMA issuer URL, or catalog/connection name). That key resolution is moved out of auth/clear into a shared resolveAuthKeyArgument, and auth/clear behaves as before. It prints the summary in text or --format json and never prints the token.
  • Docs: clients/tui/README.md, clients/mcpdo/README.md, skills/mcpdo/SKILL.md.

Screenshots

These are frames of the real AuthTab component rendered by the TUI test harness with FORCE_COLOR and converted to an image. They are not from a live OAuth session; the token state is seeded.

JWT access token:

TUI Auth tab, JWT token

Opaque access token (shows expires_in / scope from the token response):

TUI Auth tab, opaque token

Tests

  • clients/web/src/test/core/auth/accessTokenClaims.test.ts: 100% on all four dimensions for the new core module.
  • clients/tui/__tests__/AuthTab.test.tsx: JWT and opaque rendering.
  • clients/mcpdo/__tests__/connection-stored-auth.test.ts: auth/show JSON and text against a real store fixture, a token-less entry, a blank key, and a check that the token never appears in the output.
  • clients/mcpdo/__tests__/auth-names-commands.test.ts: auth/show by friendly name, and the stdio-name error.

npm run local:gate passes.

🤖 Generated with Claude Code

@cliffhall cliffhall added the v2 Issues and PRs for v2 label Nov 5, 2026
@cliffhall cliffhall linked an issue Nov 5, 2026 that may be closed by this pull request
2 tasks done
@cliffhall
cliffhall requested a balanced review from Copilot November 5, 2026 05:51

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

String-valued scp claims are not split into individual scopes, causing incorrect JSON scope lists and inconsistent text/TUI output compared with equivalent array-valued claims.

1 open issue
What changed in this PR

Adds shared access-token inspection to the TUI and mcpdo, helping diagnose OAuth failures without an external decoder. JWT claims are displayed without signature verification; opaque tokens use token-response metadata.

Changes:

  • Adds shared claim decoding, control-character stripping, and relative-time formatting.
  • Adds TUI Access Token Details and mcpdo auth/show, reusing key resolution from auth/clear.
  • Adds tests and documents both inspection surfaces.
File Description
skills/​mcpdo/​SKILL.md Documents auth/show for OAuth troubleshooting.
core/​auth/​accessTokenClaims.ts Adds shared token summaries and display formatting.
clients/​web/​src/​test/​core/​auth/​accessTokenClaims.test.ts Tests claim parsing, sanitization, and time formatting.
clients/​tui/​src/​components/​AuthTab.tsx Displays access-token details on the Auth tab.
clients/​tui/​README.md Documents token inspection in the TUI.
clients/​tui/​__tests__/​AuthTab.test.tsx Tests JWT and opaque-token rendering.
clients/​mcpdo/​src/​connection/​stored-auth.ts Reads stored tokens into display summaries.
clients/​mcpdo/​src/​connection/​mcp.ts Registers auth/show and shares auth-key resolution.
clients/​mcpdo/​src/​connection/​format-human.ts Formats human-readable token details.
clients/​mcpdo/​src/​connection/​format-connection.ts Routes auth/show text and JSON output.
clients/​mcpdo/​README.md Documents command usage and supported key forms.
clients/​mcpdo/​__tests__/​connection-stored-auth.test.ts Tests stored-token output and raw-token omission.
clients/​mcpdo/​__tests__/​auth-names-commands.test.ts Tests friendly-name resolution and stdio errors.

Review effort: Balanced

Comment thread core/auth/accessTokenClaims.ts Resolved
@cliffhall
cliffhall force-pushed the v2/feat/2845-token-claims branch from dad2195 to 4ab6019 Compare November 5, 2026 06:22
@cliffhall

Copy link
Copy Markdown
Member Author

Copilot round 1: 1 inline finding (a string-valued scp was not split into scopes). Fixed in 4ab6019 with a test, and replied in the thread. Nothing in the suppressed block. The branch is also rebased onto the current v2/main, and local:gate is green.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Time-sensitive assertions use fixture timestamps captured before execution while rendering reads the real clock, so delays can cause correct behavior to fail unless Date.now() is frozen and restored.

1 open issue
1 resolved since last review

Review effort: Balanced

Comment thread clients/tui/__tests__/AuthTab.test.tsx Resolved
@cliffhall

Copy link
Copy Markdown
Member Author

Copilot round 2: 1 inline finding (relative-time assertions could flip under test delay). Fixed in 0a560d9 with day-scale fixture offsets rather than a frozen clock (reason in the thread). Nothing suppressed. local:gate is green.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues remain for the access-token diagnostics change across the TUI and mcpdo.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

@cliffhall

Copy link
Copy Markdown
Member Author

Copilot review loop closed: round 3 was clean (no inline comments, no suppressed findings, approval recommended). Three rounds in total, with one in-scope finding fixed in each of rounds 1 and 2.

cliffhall and others added 3 commits November 5, 2026 02:18
Add core/auth/accessTokenClaims.ts: an unverified display summary of an
access token — JWT claims (iss, aud, sub, client_id/azp, scope/scp, iat,
exp with expiry relative to now), or the token response's scope and
expires_in for an opaque token. Control characters are stripped from
claim strings before they reach a terminal.

- TUI Auth tab: new Access Token Details section under OAuth Details.
- mcpdo: new auth/show <key> command (same key forms as auth/clear,
  whose key resolution is factored out and shared). Prints the summary,
  never the token, in text or --format json.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
@cliffhall
cliffhall force-pushed the v2/feat/2845-token-claims branch from 0a560d9 to d2430c9 Compare November 5, 2026 07:43
@cliffhall

Copy link
Copy Markdown
Member Author

Rebased onto v2/main to clear an import-only conflict in AuthTab.tsx with the fetch-guard refusal work (both imports kept). local:gate is green again. No functional change since the clean Copilot round.

@cliffhall
cliffhall merged commit f1e32f0 into v2/main Nov 5, 2026
10 checks passed
@cliffhall
cliffhall deleted the v2/feat/2845-token-claims branch November 5, 2026 07:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v2 Issues and PRs for v2

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TUI / mcpdo: decode and show access-token claims

2 participants