feat(ui): add ID-JAG (Okta Cross App Access) auth type to MCP server form - #34038
feat(ui): add ID-JAG (Okta Cross App Access) auth type to MCP server form#34038yassin-berriai wants to merge 1 commit into
Conversation
|
|
Greptile SummaryThis PR adds
Confidence Score: 5/5Safe to merge; the previously flagged shared-column nulling bug is correctly resolved and the new ID-JAG form integrates cleanly with the existing token-exchange infrastructure. The auth-type grouping logic correctly prevents token_exchange_endpoint and audience from being cleared when switching between the two token-exchange family members in both directions. The new IdJagFormFields component correctly splits storage between flat DB columns and the credentials blob. The only gaps are two non-blocking quality items. No files require special attention. The test file could benefit from a symmetric ID-JAG to OBO regression test, but the underlying logic is correct.
|
| Filename | Overview |
|---|---|
| ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/IdJagFormFields.tsx | New component for ID-JAG form fields; clean implementation mirroring TokenExchangeFormFields; placeholderSuffix is only applied to password fields, not to the URL endpoint fields (minor UX inconsistency in edit mode). |
| ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_server_edit.tsx | Correct fix for the previously flagged shared-column nulling bug; AUTH_TYPES_SHARING_TOKEN_EXCHANGE_COLUMNS logic handles both OBO→ID-JAG and ID-JAG→OBO directions; regression test covers the OBO→ID-JAG direction. |
| ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/create_mcp_server.tsx | Correctly adds OAUTH2_ID_JAG to AUTH_TYPES_REQUIRING_CREDENTIALS, renders IdJagFormFields when selected, and adds virtual={false} to the auth-type Select; no issues found. |
| ui/litellm-dashboard/src/components/mcp_tools/types.tsx | Adds OAUTH2_ID_JAG to the AUTH_TYPE enum; no other changes; correctly scoped. |
| ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_server_edit.test.tsx | Adds regression test for OBO→ID-JAG direction (the originally flagged bug); the symmetric ID-JAG→OBO direction is handled by the shared constant but lacks its own regression test. |
| ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/create_mcp_server.test.tsx | New test 'routes ID-JAG (Okta Cross App Access) config to the backend payload' covers the full create-form submission path including both flat and nested credential fields. |
Reviews (2): Last reviewed commit: "feat(ui): add ID-JAG (Okta Cross App Acc..." | Re-trigger Greptile
86d87db to
d360b1e
Compare
…form
Admins could configure an oauth2_id_jag MCP server only through config.yaml or
the REST API; the dashboard's Add/Edit MCP Server form had no ID-JAG option, so
the leg-2 resource token endpoint and resource indicator were unreachable from
the UI. Add an ID-JAG auth type that renders the two-leg fields (IdP token
endpoint for leg 1, resource token endpoint for leg 2, client id/secret,
audience, resource indicator, scopes), sending the credential-blob fields nested
under credentials so the existing backend persists them unchanged.
The auth-type Select is switched to virtual={false} so all options render
deterministically; the antd virtual list otherwise drops the last option once
the list grows, which is both an a11y gap and what broke the option-selection
tests.
d360b1e to
7a2b167
Compare
|
Good catch, that was a real bug. Fixed in 7a2b167. Both `oauth2_token_exchange` and `oauth2_id_jag` share the `token_exchange_endpoint` and `audience` columns, so I now treat them as a family: the shared columns are nulled only when switching to an auth type OUTSIDE that family, and the token-exchange-only columns (`subject_token_type`, `token_exchange_profile`) are nulled when leaving OBO. This fixes the token_exchange -> id_jag direction you flagged and the symmetric id_jag -> token_exchange direction (my original id_jag clause had the same defect in reverse). Added a regression test in mcp_server_edit.test.tsx ("preserves the shared leg-1 endpoint and audience when switching token exchange to ID-JAG") plus the existing switch tests still pass. @greptileai please review the current head 7a2b167 |
|
I independently verified this end to end. I built the dashboard from Public screen recording (opens without any login): https://litter.catbox.moe/1rtupq.mp4 ; durable mirror https://gofile.io/d/Eo2BoN . The animated capture and the live DB row are embedded in the PR description under Screenshots / Proof of Fix DB row from that run: |
|
Superseded. #35147 landed the ID-JAG auth type with a fuller version of this form: it adds the Client Private Key (PEM) field and the private_key_jwt path, and accepts either a client secret or a private key where this branch required the secret. Rebasing this one onto current staging would revert that work rather than add to it The one thing here that #35147 did not carry is the shared-column clearing, so an ID-JAG server converted to another auth type kept a stale token_exchange_endpoint and audience. That is now #35387, along with this branch's auth-type-switch test and the converse case it did not cover |
Relevant issues
Linear ticket
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
@greptileaito re-request a review after pushing changes)Screenshots / Proof of Fix
Captured at commit 86d87db against a live proxy (namespaced Postgres,
STORE_MODEL_IN_DB=True) with the dashboard dev server pointed at itBefore: the Add/Edit MCP Server auth-type dropdown offered
none,api_key,bearer_token,token,basic,oauth2,OAuth Token Exchange (OBO),aws_sigv4,true_passthrough,oauth_delegate. There was no way to create anoauth2_id_jagserver from the UI, so the leg-2 resource token endpoint and resource indicator (which live in the credentials blob) could only be set via config.yaml or a hand-rolled REST callAfter: selecting the new
ID-JAG (Okta Cross App Access)option renders the two-leg fields and creating the server persists them. Steps a reviewer can follow against a live proxy:+ Add New MCP Server, then+ Custom ServerStreamable HTTP, enter an upstream URL, and choose AuthenticationID-JAG (Okta Cross App Access)IdP Token Endpoint (leg 1)(e.g.https://<your-okta-domain>/oauth2/v1/token),Resource Token Endpoint (leg 2),Client ID,Client Secret, and optionallyAudience,Resource Indicator,Scopesoauth2_id_jagbadgeThe stored row confirms leg 1 and audience land in their dedicated columns and the leg-2 endpoint plus client credentials land in the (encrypted) credentials blob that the resolver reads:
Screen recording of the create flow and the auth-type dropdown are attached below
Independently verified end to end (Devin)
Independently reproduced on the current branch tip: I built the dashboard from
litellm_mcp_id_jag_ui, served it from a locally run Postgres-backed proxy (username/password login, master key never typed into the browser, no detailed-debug banner), created an MCP server through the newID-JAG (Okta Cross App Access)option with the leg-2 Resource Token Endpoint filled, saw it land in the list with theoauth2_id_jagbadge, and confirmed the row in PostgresPublic screen recording (opens without any login): https://litter.catbox.moe/1rtupq.mp4 ; durable mirror https://gofile.io/d/Eo2BoN . The direct link above is a short-lived public host (about 72 hours), so the same flow is embedded below as an animated capture that stays with the PR
Live DB row from that run, showing leg-1 and audience in their columns and the leg-2 endpoint persisted in plaintext inside the credentials blob (client id/secret encrypted at rest):
Type
🆕 New Feature
Changes
Adds
oauth2_id_jagto the dashboard'sAUTH_TYPEenum and a newIdJagFormFieldscomponent that mirrors the existingTokenExchangeFormFieldspattern. Both the create and edit MCP server forms render it when the ID-JAG auth type is selected. The fields split the way the backend stores them:token_exchange_endpoint(leg 1) andaudiencehave dedicated columns so they are flat form fields, whileid_jag_resource_token_endpoint(leg 2),id_jag_resource,client_id,client_secret, andscopesare nested undercredentialsso the existing create/update path persists them into the credentials blob with no backend change. The read path already hydrates these from the credentials blob, and I verified on a live proxy that a name-only edit preserves the whole blob (the update merges rather than replaces), so the edit form's keep-existing behavior is safeThe auth-type
Selectin both forms is switched tovirtual={false}. The dropdown is a small fixed list where virtualization buys nothing, and antd's virtual list drops the last rendered option once the list grows past its window, which hidesoauth_delegatefrom screen readers and keyboard users and is what broke the option-selection tests once a new option was addedFinal Attestation
Link to Devin session: https://app.devin.ai/sessions/3215c2fd5c304d1cae025b70a40fceef