Skip to content

@W-23757363: clarify Tableau auth/permission errors across all auth modes - #894

Open
Alon-ST-DATA wants to merge 8 commits into
mainfrom
asimantov/W-23757363-auth-error-clarity
Open

@W-23757363: clarify Tableau auth/permission errors across all auth modes#894
Alon-ST-DATA wants to merge 8 commits into
mainfrom
asimantov/W-23757363-auth-error-clarity

Conversation

@Alon-ST-DATA

Copy link
Copy Markdown
Contributor

Problem (W-23757363)

When a Tableau MCP server holds a bad/expired credential, or the request reaches the wrong server in a multi-server setup, the failure surfaced as a bare Request failed with status code 401 — or the server crashed at startup while fetching site settings. Models paraphrased both into a misleading "feature not configured" message, making a 401 auth failure indistinguishable from Admin Insights genuinely not being provisioned.

Fix

Classify raw thrown 401/403 REST errors in the shared web-tool error path (WebTool.logAndExecute) into clear, self-explanatory guidance that names the targeted site and pod. Because it lives in the shared path, it covers every auth mode — PAT, OAuth, direct-trust/connected-app, UAT, passthrough. Typed McpToolErrors (e.g. AdminOnlyError) bypass reclassification and keep their curated text.

File Change
src/utils/authErrorMessage.ts (new) Single source for 401/403 wording (buildAuthenticationErrorMessage / buildPermissionErrorMessage)
src/tools/web/tool.ts Reclassify raw thrown 401/403 in the catch; other paths byte-for-byte unchanged
src/utils/mcpSiteSettings.ts A startup 401 no longer crashes the server — logs guidance, continues with defaults (matches OAuth)
src/server/oauth/authMiddleware.ts Enrich the OAuth 401 challenge error_description with the same guidance (WWW-Authenticate unchanged)
src/tools/web/adminInsights/resolver.ts De-conflate the not-provisioned 404 message from the site-admin-role hint
docs/ New multiple-servers.md decoder table + edits to auth/oauth/admin-insights/intro

Version: 4.8.2 → 4.8.3 (patch).

Scope & risk

  • Scope: all web tools + all auth modes (not admin-only). Only resolver.ts is admin-insights-specific.
  • Risk: low / contained. Reclassification fires only when the error was thrown (not Result.Err), is not an McpToolError, and status is exactly 401/403. Success paths, ZodiosValidationError, and all typed errors are unchanged.
  • 403 wording deliberately does not assert "not a missing feature" — Tableau REST can return 403 for a disabled capability too, so the message allows for role/permission or capability-not-enabled.

Tests

  • Full unit suite 2903 pass. New: authErrorMessage.test.ts, authMiddleware.test.ts; extended tool.test.ts, mcpSiteSettings.test.ts, resolver.test.ts (raw 401, raw 403, curated-403 passthrough, non-auth 503 passthrough, telemetry error_code, startup-401-degrades, 404 de-conflation).
  • Live e2e on site kiwimoussetdp2: 401-at-call, 401-at-startup (no crash), 404 not-provisioned, OAuth transport 401 — all verified.

Known follow-up (out of scope, noted intentionally)

The OAuth invalid_token 401 path in authMiddleware.ts returns 401 + enriched error_description but does not set a WWW-Authenticate header (only the no-token 401 and insufficient-scope 403 do). Pre-existing; RFC 6750 suggests it should. Left for a separate change to keep this PR scoped to W-23757363.

🤖 Generated with Claude Code

A bad or expired credential surfaced as a bare "Request failed with status
code 401" (or crashed the server at startup while fetching site settings),
which models paraphrased into a misleading "feature not configured" message
— indistinguishable from Admin Insights genuinely not being provisioned.

Classify raw thrown 401/403 REST errors in the shared web-tool error path
into clear, self-explanatory guidance naming the targeted site and pod. This
lives in WebTool.logAndExecute, so it covers every auth mode (PAT, OAuth,
direct-trust, UAT, passthrough). Typed McpToolErrors (e.g. AdminOnlyError)
bypass reclassification and keep their curated text.

- src/utils/authErrorMessage.ts (new): single source for 401/403 wording
- src/tools/web/tool.ts: reclassify raw thrown 401/403 in the catch
- src/utils/mcpSiteSettings.ts: a startup 401 no longer crashes the server —
  it logs guidance and continues with defaults (matches OAuth behavior)
- src/server/oauth/authMiddleware.ts: enrich the OAuth 401 challenge
  error_description with the same guidance (WWW-Authenticate unchanged)
- src/tools/web/adminInsights/resolver.ts: de-conflate the not-provisioned
  404 message from the site-admin-role hint
- docs: new multiple-servers.md decoder table + auth/oauth/admin-insights/intro
- version 4.8.2 -> 4.8.3 (patch)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@Akash-Rastogi Akash-Rastogi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[Akash's agent] Not approving yet — two merge blockers:

  1. build (24.x) is red (see inline on authMiddleware.ts): the enriched OAuth error_description broke two exact-match assertions in tests/oauth/embedded-authz/oauth.test.ts (lines 71 and 761) that this PR didn't update. Deterministic, not a flake.
  2. check-title is failing — the title is W-23757363:, but the repo's check requires the @W-23757363: form. Please retitle.

The classification approach and authErrorMessage.ts wording look sound, and the reclassification in tool.ts is correctly scoped to raw, non-McpToolError, exactly-401/403 errors — so other tools' error paths are unchanged. Happy to approve once the build is green and the title is fixed.

Comment thread src/server/oauth/authMiddleware.ts
@Alon-ST-DATA Alon-ST-DATA changed the title W-23757363: clarify Tableau auth/permission errors across all auth modes @W-23757363: clarify Tableau auth/permission errors across all auth modes Sep 8, 2026
Alon-ST-DATA and others added 5 commits September 8, 2026 09:39
…_description

The PR enriched the OAuth 401 error_description strings (no-token and
invalid_token) in authMiddleware.ts with the shared multi-server guidance,
but the embedded-authz suite still pinned the old text byte-for-byte and
failed in CI. That suite runs under test:oauth:embedded (not npm test), so a
unit-only run stayed green while build (24.x) went red.

Replace the two toEqual assertions with toMatchObject({ error }) plus
error_description.toContain(<stable substring>) so the description text is no
longer pinned byte-for-byte. Test-only: no production change, no version bump.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
….8.3)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…clarity' into asimantov/W-23757363-auth-error-clarity

@Akash-Rastogi Akash-Rastogi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[Akash's agent] LGTM — approving. Both blockers from my prior review are cleared:

  • Build green — the two embedded-authz assertions now use toMatchObject({ error }) + error_description.toContain(...) (commit 1cb67409), the robust fix that no longer pins the enriched description byte-for-byte. build (24.x) and build (>=22.7.5 <23) both pass.
  • Title fixed to @W-23757363:check-title green.

The classification logic I reviewed last round is unchanged and sound: authErrorMessage.ts wording is clear (403 correctly hedges role/permission-or-capability and says "don't re-authenticate"), and the raw-401/403 reclassification in tool.ts is scoped to non-McpToolError errors only, so other tools' error paths are untouched. Full CI matrix green. Nice work.

Alon-ST-DATA and others added 2 commits September 9, 2026 17:10
…auth-error-clarity

# Conflicts:
#	package-lock.json
#	package.json
The allData 403/404 test asserted the raw Axios message for both statuses.
After the W-23757363 auth-error-clarity change, logAndExecute rewrites 403
into the shared 'Permission denied (403)' guidance while leaving other
statuses (404) raw. Assert the per-status expected text.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

**Issue 3: Multiple configured servers — a tool call may target the wrong or unauthenticated server**

- **Problem:** When more than one Tableau MCP server is configured, the AI client may send a tool call to a different server than you intended — including one that is not authenticated. The resulting `401` can be summarized by the AI as a vague "feature not configured" message.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why is it that a 401 Unauthorized expected with this issue? When there are multiple servers connected, a client does not user credentials from one server when calling the other right? It uses the credentials that pertains to the connection. So it shouldn't be 401 Unauthorized, it would be more like 404 Not Found when you specify a target. For example, if I ask it to get me metadata for a Datasource belonging to MCP server A, but instead it calls MCP server B. The request will be authorized right, just fail with 404 because the datasource was not found.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I hear your point @stephendeoca, but this can be debatable. You can look at it as we have an authenticated user (for a session on server A) that cannot see resources because no authorization on target server B... catching this error with proper logging.
For me, having 404 error hide the real auth error.

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.

3 participants