ui: add OAuth2 consent page and MCP server auth mode settings#4510
Conversation
|
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (7)
🚧 Files skipped from review as they are similar to previous changes (7)
📝 WalkthroughSummary by CodeRabbit
WalkthroughAdds a new ChangesOAuth2 Consent Page
MCP Server Authentication Configuration
Sequence Diagram(s)sequenceDiagram
participant Browser
participant OAuth2ConsentPage
participant sessionStorage
participant oauth2ConsentApi as RTK Query (oauth2ConsentApi)
Browser->>OAuth2ConsentPage: GET /oauth/consent?flow=flowId
OAuth2ConsentPage->>sessionStorage: restore temp token keyed by flowId
OAuth2ConsentPage->>oauth2ConsentApi: getOAuth2ConsentFlow(flowId)
oauth2ConsentApi-->>OAuth2ConsentPage: OAuth2ConsentFlowDetail (modes, expires_at)
OAuth2ConsentPage->>OAuth2ConsentPage: render user / vk / session mode selection
OAuth2ConsentPage->>oauth2ConsentApi: submitOAuth2ConsentFlow({ mode, value })
oauth2ConsentApi-->>OAuth2ConsentPage: { redirect_url }
OAuth2ConsentPage->>Browser: window.location = redirect_url
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@ui/app/oauth/consent/page.tsx`:
- Around line 275-283: The formatExpiry function does not validate that the
parsed date is valid before using it in calculations. When an invalid ISO string
is passed, new Date(iso).getTime() returns NaN, which then gets propagated
through the arithmetic operations and renders as "in NaN minutes". Add a check
immediately after calculating diffMs to verify it is not NaN, and if it is NaN,
return a safe default value such as "soon" before proceeding with the remaining
logic.
- Around line 290-292: The inner div with the className containing "bg-card
w-1/3 rounded-sm border p-8 shadow-sm" uses a fixed width of w-1/3 which is not
responsive on mobile screens. Replace the w-1/3 class with a responsive width
approach that uses full width (w-full) on small screens and constrains the width
on larger screens. Consider using a combination of w-full with a max-width
constraint (such as max-w-sm or max-w-md) and add responsive breakpoint
modifiers (like md:w-1/3) to achieve the desired layout on different screen
sizes.
- Around line 149-264: Add data-testid attributes to all new interactive
controls in the consent flow to enable stable Playwright E2E test selectors.
Specifically, add data-testid to: the "Continue as" button that calls
handleSubmit("user"), the login link in the sign-in section, the virtual key
input field (id="vk-input"), the "Connect with key" button that calls
handleSubmit("vk"), and the "Continue without an identity" button that calls
handleSubmit("session"). Use descriptive, stable identifiers that clearly
indicate the purpose of each element to support E2E test coverage.
- Around line 134-265: The consent page currently renders nothing when no
authentication modes are available (when all conditions like hasUser, hasVK, and
hasSession evaluate to false). Add an empty state UI that displays when none of
the consent modes can be shown. This should check if no modes are available and
render a message informing the user that no authentication options are currently
available. Place this empty state within the space-y-3 div container,
conditional on the absence of all available modes (user mode, VK mode, and
session mode).
In `@ui/app/workspace/config/views/mcpView.tsx`:
- Around line 171-189: The validation in handleAuthCodeTTLChange and
handleAccessTokenTTLChange currently only checks if the parsed number is greater
than 0, but the input fields declare a minimum of 60 seconds. Update both
handlers to also enforce the minimum of 60 seconds by changing the condition
from num > 0 to num >= 60 when validating auth_code_ttl and access_token_ttl in
the oauth2_server_config. Additionally, add validation logic in the handleSave
function to check both TTL values against the 60-second minimum and display a
toast notification to the user if either value falls below the required minimum,
providing explicit feedback about the constraint.
- Around line 91-99: The issuer URL comparison only checks the .value property
of the EnvVar, missing changes to env_var and from_env fields. This prevents the
Save Changes button from being enabled when switching between literal values and
environment variables. Replace the direct comparison of issuer_url?.value with a
call to the envVarEquals function (reusing the same approach used for the
clientURLChanged comparison earlier in the condition chain) to properly compare
the full EnvVar object including all fields.
In `@ui/lib/store/apis/oauth2ConsentApi.ts`:
- Around line 22-30: The flowId parameter is being directly interpolated into
API endpoint paths without URL encoding in both the getOAuth2ConsentFlow and
submitOAuth2ConsentFlow methods. This allows reserved characters in the
user-controlled flowId to alter the requested route. Wrap the flowId with
encodeURIComponent() before inserting it into the URL paths for both the query
and mutation endpoints to ensure proper URL encoding.
In `@ui/lib/utils/loginGoto.ts`:
- Line 29: The value.startsWith("/oauth/consent") check in the loginGoto.ts file
is too permissive because it matches unintended paths like
"/oauth/consent-anything". Examine how the /workspace path checks are
implemented in the same file to understand the proper restriction pattern, then
apply the same approach to the /oauth/consent check to ensure it only matches
the intended paths (likely by checking for an exact match or verifying a path
separator follows the prefix).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 3c974628-a163-403f-b346-da529229f20f
📒 Files selected for processing (7)
ui/app/oauth/consent/layout.tsxui/app/oauth/consent/page.tsxui/app/workspace/config/views/mcpView.tsxui/lib/store/apis/index.tsui/lib/store/apis/oauth2ConsentApi.tsui/lib/types/config.tsui/lib/utils/loginGoto.ts
98169a4 to
be01ec8
Compare
3d76e6a to
e5a9a8f
Compare
be01ec8 to
9282613
Compare
e5a9a8f to
47cce08
Compare
47cce08 to
577e9c3
Compare
9282613 to
2a42dc9
Compare
577e9c3 to
87046c1
Compare
2a42dc9 to
1c19dfb
Compare
87046c1 to
c6c30c4
Compare
1c19dfb to
0ecdc90
Compare
0ecdc90 to
4178622
Compare
c6c30c4 to
1525b40
Compare
1525b40 to
3ab71d6
Compare

Summary
Adds an OAuth2 consent page and supporting configuration to allow MCP clients (e.g.
claude mcp add) to authenticate via a browser-based OAuth flow. Anonymous visitors arrive at/oauth/consent?flow=<id>with a short-lived temp token embedded in the URL fragment, choose how they want to identify themselves (signed-in user, virtual key, or anonymous session), and are redirected back to the MCP client with an authorization code.Changes
/oauth/consentroute — New standalone page (layout.tsx+page.tsx) that renders outside the dashboard chrome. It wraps itself withThemeProvider,ReduxProvider,NuqsAdapter, andToasterdirectly since it does not inherit them fromClientLayout.TempTokenScopeextracts the#t=…fragment and attaches it asX-Bifrost-Temp-Tokenon every API call so the consent APIs can authenticate the anonymous visitor.ConsentViewfetches the flow details and presents up to three authentication options: continuing as the signed-in user, entering a virtual key, or proceeding anonymously. It preserves the temp token across the login redirect viasessionStorageso users who choose to sign in are returned to the correct flow.oauth2ConsentApi— New RTK Query endpoints (GETandPUT/oauth2/consent/flows/:flowId) for fetching flow details and submitting the chosen identity mode.mcp_server_auth_modeselector (headers/both/oauth) with contextual warnings: switching tooauthdisables VK/header access; downgrading back toheadersrevokes all existing OAuth JWTs. OAuth2 server settings (issuer URL, auth code TTL, access token TTL) are revealed when the mode isbothoroauth.CoreConfigtypes — Addedmcp_server_auth_modeandoauth2_server_config(issuer URL, auth code TTL, access token TTL) to the config type and dirty-check logic.loginGoto—/oauth/consentis now treated as a valid post-login redirect destination.Type of change
Affected areas
How to test
claude mcp add --transport sse <bifrost-url>/mcp(or equivalent). The client should redirect to/oauth/consent?flow=<id>#t=<token>.sk-bf-…key and confirm a successful redirect.mcp_server_auth_modebetweenheaders,both, andoauthand verify the correct warnings appear and the OAuth2 server settings section shows/hides accordingly.cd ui pnpm i pnpm buildBreaking changes
Setting
mcp_server_auth_modetooauthdisables virtual key and header-based MCP authentication immediately. All existing MCP integrations using VK, api-key, or session headers will stop working until clients re-authenticate via the OAuth consent flow. Setting the mode back toheadersfrombothoroauthinvalidates all previously issued OAuth JWTs and refresh tokens.Security considerations
#t=…) is passed in the URL fragment and never sent to the server by the browser directly; it is extracted client-side and attached as a custom header (X-Bifrost-Temp-Token), limiting exposure in server logs.setSuppressGlobal401is called when restoring a temp token fromsessionStorageafter a login redirect to prevent the global 401 handler from clearing the session prematurely during the consent flow.Checklist
docs/contributing/README.mdand followed the guidelines