Skip to content

[Fix] UI - Allow Proxy Admin Viewer to access /api-keys page - #26690

Closed
kimsehwan96 wants to merge 3 commits into
BerriAI:litellm_internal_stagingfrom
kimsehwan96:kimsehwan96/fix-admin-viewer-api-keys-page-access
Closed

[Fix] UI - Allow Proxy Admin Viewer to access /api-keys page#26690
kimsehwan96 wants to merge 3 commits into
BerriAI:litellm_internal_stagingfrom
kimsehwan96:kimsehwan96/fix-admin-viewer-api-keys-page-access

Conversation

@kimsehwan96

@kimsehwan96 kimsehwan96 commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

Relevant issues

Fixes #26689

Linear ticket

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have Added testing in the tests/test_litellm/ directory, Adding at least 1 test is a hard requirement - see details
  • My PR passes all unit tests on make test-unit
  • My PR's scope is as isolated as possible, it only solves 1 specific problem
  • I have requested a Greptile review by commenting @greptileai and received a Confidence Score of at least 4/5 before requesting a maintainer review

Delays in PR merge?

If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).

CI (LiteLLM team)

CI status guideline:

  • 50-55 passing tests: main is stable with minor issues.
  • 45-49 passing tests: acceptable but needs attention
  • <= 40 passing tests: unstable; be careful with your merges and assess the risk.
  • Branch creation CI run
    Link:

  • CI run for the last commit
    Link:

  • Merge / cherry-pick CI run
    Links:

Screenshots / Proof of Fix

AS-IS

스크린샷 2026-04-28 오후 8 23 16

TO-BE

스크린샷 2026-04-28 오후 8 09 41

Type

🐛 Bug Fix

Changes

Remove the entry-level "Access Denied" gate in ui/litellm-dashboard/src/components/user_dashboard.tsx that was hard-blocking proxy_admin_viewer from /ui/?page=api-keys.

The backend (admin_viewer_routes, route_checks, key handler) already allows /key/list and /key/info for this role, and component-level guards (rolesWithWriteAccess in ui/litellm-dashboard/src/utils/roles.ts) already hide Create / Edit / Delete affordances — so the gate was redundant and inconsistent with the role's documented intent.

There's a useEffect that was forcing page to "usage" for Admin Viewer right after JWT decode, so even if you went to /ui?page=api-keys it would silently rewrite the URL.

That was probably a workaround for the Access Denied screen (push viewers somewhere they can actually see something).

Now that the gate is gone, viewers can stay on the keys page in read-only mode, so the redirect isn't needed anymore. also the e2e below would fail without removing it.

Tests

  • vitest: UserDashboard renders the keys table for both Admin Viewer and proxy_admin (no Access Denied screen).
  • e2e:
    • as proxy_admin_viewer, /ui?page=api-keys shows the keys table, other users' seeded keys are visible (admin scope), and the Create New Key button is hidden
    • clicking into a key detail view works, but Regenerate Key / Delete Key / Edit Settings buttons are hidden.

The /api-keys page was hard-blocking proxy_admin_viewer at the user_dashboard entry point with an "Access Denied" screen, contradicting the role's own description ("view all keys, view all spend") in litellm/proxy/_types.py and the backend route_checks/admin_viewer_routes/key handler that already allow /key/list and /key/info for this role. Component-level guards (rolesWithWriteAccess in ui/litellm-dashboard/src/utils/roles.ts) already hide the Create / Edit / Delete affordances for this role, so removing the entry-level gate makes the UI consistent with the backend and with sibling viewer-open features (Audit Logs BerriAI#23419, Spend Logs BerriAI#26583).
@greptile-apps

greptile-apps Bot commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR removes a redundant frontend gate in user_dashboard.tsx that was showing an "Access Denied" screen to proxy_admin_viewer users trying to access /ui/?page=api-keys, and removes the companion useEffect redirect in page.tsx that was silently pushing viewers to the "usage" page. The backend already permits /key/list and /key/info for this role, and component-level guards in roles.ts already suppress write affordances — so both the gate and the redirect were unnecessary. Unit tests and an e2e spec are added to prevent regressions.

Confidence Score: 5/5

Safe to merge — change is a targeted UI gate removal backed by existing backend role checks and new test coverage.

Only two small deletions and additive tests. Backend authorization for /key/list already covers the proxy_admin_viewer role; component-level guards in roles.ts preserve read-only enforcement. No new network paths, no schema changes, no security boundary changes.

No files require special attention.

Important Files Changed

Filename Overview
ui/litellm-dashboard/src/components/user_dashboard.tsx Removes the early-return "Access Denied" block for Admin Viewer role; the component now falls through to render the keys view for all authenticated roles.
ui/litellm-dashboard/src/app/page.tsx Removes the Admin Viewer → "usage" page redirect from the JWT-decode useEffect; consistent with the gate removal so viewers land on whatever page they navigated to.
ui/litellm-dashboard/src/components/user_dashboard.test.tsx Adds screen import and two role-based rendering tests verifying Admin Viewer and Admin both reach the keys table without an Access Denied screen; all networking mocked, no real calls.
ui/litellm-dashboard/e2e_tests/tests/proxy-admin-viewer/api-keys-access.spec.ts New Playwright e2e spec verifying read-only access for proxy_admin_viewer: keys table visible, Create/Regenerate/Delete/Edit buttons hidden.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["User navigates to /ui?page=api-keys"] --> B["page.tsx: JWT decode useEffect"]
    B -->|"Before PR: userRole == 'Admin Viewer'"| C["setPage('usage') — redirect away REMOVED"]
    B -->|"After PR: all roles"| D["userRole set from token, page unchanged"]
    D --> E["UserDashboard renders"]
    E -->|"Before PR: userRole == 'Admin Viewer'"| F["Return Access Denied REMOVED"]
    E -->|"After PR: all roles"| G["Render keys view"]
    G --> H{"rolesWithWriteAccess check"}
    H -->|"Admin Viewer"| I["VirtualKeysTable (read-only) - No Create / Edit / Delete / Regenerate buttons"]
    H -->|"Admin / proxy_admin"| J["VirtualKeysTable + write affordances"]
Loading

Reviews (3): Last reviewed commit: "[Test] UI - Cover proxy_admin_viewer acc..." | Re-trigger Greptile

@codecov

codecov Bot commented Apr 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Removes the JWT-decode useEffect that overrode `?page=api-keys` to "usage" for Admin Viewer. Backend already allows /key/list and /key/info for this role.
vitest: assert UserDashboard renders the keys table for both Admin Viewer and proxy_admin (no Access Denied).
e2e: viewer sees seeded keys (admin scope), Create button is hidden, key detail view loads without Regenerate / Delete / Edit.
@kimsehwan96
kimsehwan96 force-pushed the kimsehwan96/fix-admin-viewer-api-keys-page-access branch from 72b4d2a to e232c9e Compare April 28, 2026 23:38
@kimsehwan96

Copy link
Copy Markdown
Contributor Author

Related changes are already merged with #26846. So I close this PR

@kimsehwan96 kimsehwan96 closed this May 4, 2026
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.

[Bug]: UI: proxy_admin_viewer is hard-blocked from /api-keys page despite backend allowing /key/list

1 participant