Skip to content

feat(web): add Forward-user-identity toggle to MCP provider modal#36840

Open
CourTeous33 wants to merge 11 commits into
mainfrom
feat/mcp-token-transfer-web
Open

feat(web): add Forward-user-identity toggle to MCP provider modal#36840
CourTeous33 wants to merge 11 commits into
mainfrom
feat/mcp-token-transfer-web

Conversation

@CourTeous33
Copy link
Copy Markdown
Contributor

Summary

  • Exposes the M2 backend flags (feat(api): add MCP user-identity forwarding #36839) as a Switch on the MCP provider create/edit modal so workspace admins can opt in to enterprise SSO identity-forwarding per provider.
  • The toggle lives between Server Identifier and the Authentication / Headers / Configurations tabs. When ON, the modal sends forward_user_identity=true + identity_mode="idp_token" on save; the backend persists them on tool_mcp_providers and overrides the static Authorization (from Auth/Headers) at invoke time with the per-user JWT.
  • en-US + zh-Hans strings added; other locales fall back to en-US.

Depends on

Test plan

  • Open the MCP provider edit modal and verify the new toggle renders between Server Identifier and the Auth tabs, with the helper text underneath.
  • Flip ON, save, reopen the modal — toggle remembers its state (round-trips through GET).
  • Flip OFF, save, reopen — toggle hydrates back to OFF.
  • With feat(api): add MCP user-identity forwarding #36839 merged: flipping ON for a provider whose calling user has a valid SSO session results in the MCP server seeing the forwarded user identity (verified via JWKS).
  • zh-Hans locale shows the translated strings.

Exposes the M2 backend flags as a switch on the MCP provider create/edit
modal so workspace admins can opt in to enterprise SSO identity-forwarding
per provider. When the toggle flips on, the modal sends
forward_user_identity=true + identity_mode="idp_token" to the console API
(which the M2 backend persists on tool_mcp_providers).

- The toggle lives between Server Identifier and the Authentication tabs;
  it overrides the static Authorization (from Auth/Headers) at invoke time.
- The form-state hook hydrates from the GET response so editing preserves
  the previous choice across sessions.
- en-US + zh-Hans strings added; other locales fall back to en-US.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@dosubot dosubot Bot added size:M This PR changes 30-99 lines, ignoring generated files. feat:webapp Ready-to-use AI web app. Also the "Preview" / "Debug & Preview" inside the orchestrate page. javascript labels May 30, 2026
@github-actions github-actions Bot added the web This relates to changes on the web. label May 30, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented May 30, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 85.83%. Comparing base (a8f009a) to head (01da1a4).

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #36840      +/-   ##
==========================================
- Coverage   85.95%   85.83%   -0.13%     
==========================================
  Files        4602     4578      -24     
  Lines      227270   222029    -5241     
  Branches    41797    41155     -642     
==========================================
- Hits       195345   190571    -4774     
+ Misses      28105    27830     -275     
+ Partials     3820     3628     -192     
Flag Coverage Δ
dify-ui 95.57% <ø> (ø)
web 86.63% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

CourTeous33 and others added 3 commits May 29, 2026 20:02
Move the M3 forwardUserIdentity / forwardUserIdentityTip entries to their
alphabetical position (between editTitle and headerKey) so the lint rule
`jsonc/sort-keys` passes.

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

Three review items rolled into one commit:

1. Gate the Forward-user-identity toggle behind enterprise SSO capability.
   The modal reads systemFeatures via useSuspenseQuery and disables the
   Switch (with a different helper line) when sso_enforced_for_signin is
   false — so non-Enterprise users can't flip it on and immediately collide
   with the backend's 428 "no stored refresh token" path. The submit
   payload also clamps to false/"off" when SSO is unavailable as a
   defence against pre-existing rows whose toggle was previously on.

2. Give the Switch an accessible name via aria-labelledby pointing at the
   visible label span. Matches what screen readers expect; consistent with
   the new id="mcp-forward-user-identity-label" wiring.

3. Add tests:
   - Hook: default-off in create, hydrate from data.forward_user_identity
     in edit, setter round-trips.
   - Modal: helper text varies with SSO capability, default submit sends
     identity_mode "off", flipped switch sends "idp_token", and an
     SSO-unavailable submit forces "off" even if data carried it on.

The modal tests had to learn how to mock systemFeaturesQueryOptions and
pre-populate the QueryClient cache (useSuspenseQuery needs synchronous data),
hence the small test-infra additions at the top of modal.spec.tsx.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Simplicity pass — no behavior changes:

- Drop the 4-line "Capability gate" comment block above the
  systemFeaturesQueryOptions hook; the variable name
  `isForwardIdentitySupported` is self-explanatory.
- Shrink the submit-side clamp comment from 2 lines to 1, focused on the
  load-bearing reason (edit-mode hydration can carry true).

Kept the `&& isForwardIdentitySupported` on the Switch `checked` prop
even though `disabled` already prevents UI flips: without it, editing a
provider whose stored toggle is on while SSO is currently off would
render a checked-but-disabled switch next to an "unavailable" helper
string — visually inconsistent.

Tests unchanged, 101/101 pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@lyzno1 lyzno1 removed the javascript label Jun 3, 2026
CourTeous33 and others added 7 commits June 3, 2026 16:28
User-requested behavior change: when SSO is not configured for sign-in
(`sso_enforced_for_signin=false` — i.e. non-Enterprise installs), the
toggle and its entire wrapper should not render at all, rather than
render disabled with an explanatory string. Existing edit-mode clamp on
submit (`forward_user_identity && isForwardIdentitySupported`) still
covers the case where a row carries a stale `true` after SSO got
removed.

- Wrap the whole Forward-user-identity <div> in
  `{isForwardIdentitySupported && (...)}`.
- Drop `disabled` and the helper-string variant from the Switch — the
  block either renders fully or not at all.
- Remove the now-unused `forwardUserIdentityUnavailable` i18n key from
  en-US and zh-Hans.
- Update systemFeaturesQueryOptions import to new location
  (`@/features/system-features/client`) after main reorg, and update
  the test mock path to match.

Tests: 100/100 pass. Replaces "shows unavailable helper" / "shows tip"
with "does not render when SSO is not configured" / "renders toggle and
tip when SSO is configured"; clamp test kept (still valid via the
submit-side check).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The toggle was previously gated only on `sso_enforced_for_signin`. SAML
satisfies that — but SAML has no refresh_token model, so the enterprise
side returns disabledSSOTokenManager → ErrSSODisabled → 503 sso_disabled
at runtime. Users could turn the toggle on and only discover the
problem at first invocation.

Gate on protocol being refresh-capable (OIDC or OAuth2) instead. Uses
the existing systemFeatures.sso_enforced_for_signin_protocol field — no
new API surface.

- Defines MCP_FORWARDING_CAPABLE_PROTOCOLS as a module-scope const so
  the same allowlist is available if a future feature needs it.
- Adds two tests: SAML hides the toggle even when sso_enforced is true;
  OAuth2 shows it the same as OIDC.
- Refactors existing "SSO on" tests to use a `enableRefreshCapableSSO`
  helper that sets both fields, so the protocol gate is always honored.

102/102 tests pass (was 100; +2 new).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ESLint's `style/indent-binary-ops` rejected the multi-line `=` + `&&`
chain on the isForwardIdentitySupported assignment (Style Check / TS Common
failed with "Expected indentation of 6 spaces" at modal.tsx:91).

Splitting the protocol cast onto a separate `ssoProtocol` line lets the
condition fit on one line, which both reads more linearly and dodges
the binary-op-continuation rule entirely. No behavior change; 102/102
vitest specs still pass.
…ty_mode (#36840)

API PR #36839 collapses the redundant `forward_user_identity` boolean
into the `identity_mode` enum — there's only one knob now. Mirror
that on the web side:

- types/ + service: stop declaring and sending forward_user_identity
- modal: omit it from the create/update payload; identity_mode alone
  drives backend state
- hook: hydrate the local toggle from `data.identity_mode !== 'off'`
  instead of the dropped bool
- tests: assert the new payload shape and the new hydration source

UI surface (the toggle label, switch state name) is unchanged; the
boolean lives only in component state and gets translated to
identity_mode at submit time.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat:webapp Ready-to-use AI web app. Also the "Preview" / "Debug & Preview" inside the orchestrate page. size:M This PR changes 30-99 lines, ignoring generated files. web This relates to changes on the web.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants