chore(web): Validate OAuth scopes for MCP access#1396
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds ChangesMCP OAuth Scope Enforcement
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…s-token-scope-validation-in-resource-server # Conflicts: # packages/web/src/app/api/(server)/ee/.well-known/oauth-protected-resource/[...path]/route.ts # packages/web/src/app/api/(server)/ee/mcp/route.ts # packages/web/src/app/api/(server)/ee/oauth/token/route.ts # packages/web/src/app/oauth/authorize/components/consentScreen.tsx # packages/web/src/app/oauth/authorize/page.tsx # packages/web/src/ee/features/oauth/actions.ts # packages/web/src/ee/features/oauth/server.ts # packages/web/src/middleware/withAuth.test.ts # packages/web/src/middleware/withAuth.ts
…n-in-resource-server
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@packages/web/src/app/oauth/authorize/page.tsx`:
- Line 20: Normalize the OAuth `scope` query param in `authorize/page.tsx`
before passing it to `resolveGrantedOAuthScopes()`, since Next.js 16 may provide
repeated values as `string[]` and that helper will fail on arrays. Update the
page’s query-param handling to treat `scope` the same way as `resource` and
`dpop_jkt`, and replace the unsafe `new URLSearchParams(params as Record<string,
string>)` usage for the callback URL with explicit string-safe construction so
array values are handled correctly.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6369ba85-ed38-430b-9192-af298b6e071d
📒 Files selected for processing (20)
CHANGELOG.mdpackages/db/prisma/migrations/20260629190000_backfill_sourcebot_mcp_oauth_scope/migration.sqlpackages/db/prisma/schema.prismapackages/web/src/__mocks__/prisma.tspackages/web/src/app/api/(server)/ee/.well-known/oauth-authorization-server/route.tspackages/web/src/app/api/(server)/ee/.well-known/oauth-protected-resource/[...path]/route.tspackages/web/src/app/api/(server)/ee/mcp/route.tspackages/web/src/app/api/(server)/ee/oauth/token/route.tspackages/web/src/app/oauth/authorize/components/consentScreen.tsxpackages/web/src/app/oauth/authorize/page.tsxpackages/web/src/ee/features/oauth/actions.tspackages/web/src/ee/features/oauth/constants.test.tspackages/web/src/ee/features/oauth/constants.tspackages/web/src/ee/features/oauth/server.test.tspackages/web/src/ee/features/oauth/server.tspackages/web/src/lib/apiHandler.test.tspackages/web/src/lib/errorCodes.tspackages/web/src/lib/serviceError.tspackages/web/src/middleware/withAuth.test.tspackages/web/src/middleware/withAuth.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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
`@packages/db/prisma/migrations/20260630005335_add_oauth_scope_to_authorization_code/migration.sql`:
- Line 2: The new scope field for OAuth authorization codes is defaulting to an
empty string, which will propagate the wrong scope into tokens; update the
authorization-code migration to backfill with the canonical MCP scope instead,
and make the same default change in the Prisma schema so
`OAuthAuthorizationCode` consistently uses `mcp` for existing and future rows.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 0c8407ea-82ef-47b6-a4be-2bea5dd475d4
📒 Files selected for processing (11)
packages/db/prisma/migrations/20260630005335_add_oauth_scope_to_authorization_code/migration.sqlpackages/db/prisma/schema.prismapackages/web/src/app/oauth/authorize/components/consentScreen.tsxpackages/web/src/app/oauth/authorize/page.tsxpackages/web/src/ee/features/oauth/actions.tspackages/web/src/ee/features/oauth/constants.tspackages/web/src/ee/features/oauth/server.test.tspackages/web/src/ee/features/oauth/server.tspackages/web/src/ee/features/oauth/utils.test.tspackages/web/src/ee/features/oauth/utils.tspackages/web/src/middleware/withAuth.ts
✅ Files skipped from review due to trivial changes (1)
- packages/web/src/ee/features/oauth/constants.ts
🚧 Files skipped from review as they are similar to previous changes (4)
- packages/web/src/ee/features/oauth/actions.ts
- packages/web/src/app/oauth/authorize/page.tsx
- packages/web/src/app/oauth/authorize/components/consentScreen.tsx
- packages/web/src/middleware/withAuth.ts
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/web/src/app/api/(server)/ee/mcp/route.ts (1)
34-45: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winEscape quoted
WWW-Authenticateparameter values.Line 44 injects
error.messageinside a quoted auth-param without escaping quotes or backslashes, which can produce a malformed OAuth challenge.Proposed fix
+function quoteAuthParam(value: string): string { + return `"${value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`; +} + function mcpOAuthChallenge(scheme: 'Bearer' | 'DPoP', error: ServiceError): string { const issuer = env.AUTH_URL.replace(/\/$/, ''); const params = [ - 'realm="Sourcebot"', - `resource_metadata_uri="${issuer}/.well-known/oauth-protected-resource/api/mcp"`, - `scope="${SOURCEBOT_MCP_OAUTH_SCOPE}"`, + `realm=${quoteAuthParam('Sourcebot')}`, + `resource_metadata_uri=${quoteAuthParam(`${issuer}/.well-known/oauth-protected-resource/api/mcp`)}`, + `scope=${quoteAuthParam(SOURCEBOT_MCP_OAUTH_SCOPE)}`, ]; if (error.errorCode === ErrorCode.OAUTH_INSUFFICIENT_SCOPE) { params.push('error="insufficient_scope"'); - params.push(`error_description="${error.message}"`); + params.push(`error_description=${quoteAuthParam(error.message)}`); }🤖 Prompt for 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. In `@packages/web/src/app/api/`(server)/ee/mcp/route.ts around lines 34 - 45, The mcpOAuthChallenge helper is building a quoted WWW-Authenticate challenge value with raw error.message, which can break the header when the message contains quotes or backslashes. Update mcpOAuthChallenge to escape auth-param values before pushing error_description (and any other quoted params) into the params array, using a small helper or inline escaping in the same function. Keep the fix localized to mcpOAuthChallenge and ensure the resulting header string remains valid for OAuth errors.
🧹 Nitpick comments (1)
packages/web/src/app/api/(server)/ee/mcp/route.ts (1)
115-115: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse the canonical MCP OAuth scope constant for enforcement.
The challenge advertises
SOURCEBOT_MCP_OAUTH_SCOPE, but the route enforces a separate'mcp'literal. Use the same constant to avoid contract drift.Proposed fix
- }, { requiredOAuthScopes: ['mcp'] }) + }, { requiredOAuthScopes: [SOURCEBOT_MCP_OAUTH_SCOPE] }) ... - }, { requiredOAuthScopes: ['mcp'] }) + }, { requiredOAuthScopes: [SOURCEBOT_MCP_OAUTH_SCOPE] })Also applies to: 159-159
🤖 Prompt for 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. In `@packages/web/src/app/api/`(server)/ee/mcp/route.ts at line 115, The MCP route is enforcing a hardcoded 'mcp' OAuth scope instead of the canonical SOURCEBOT_MCP_OAUTH_SCOPE constant, which can drift from the advertised challenge scope. Update the requiredOAuthScopes configuration in the MCP route handler to use SOURCEBOT_MCP_OAUTH_SCOPE everywhere the scope is enforced, including the other matching location in this file, so the challenge and route stay aligned.
🤖 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.
Outside diff comments:
In `@packages/web/src/app/api/`(server)/ee/mcp/route.ts:
- Around line 34-45: The mcpOAuthChallenge helper is building a quoted
WWW-Authenticate challenge value with raw error.message, which can break the
header when the message contains quotes or backslashes. Update mcpOAuthChallenge
to escape auth-param values before pushing error_description (and any other
quoted params) into the params array, using a small helper or inline escaping in
the same function. Keep the fix localized to mcpOAuthChallenge and ensure the
resulting header string remains valid for OAuth errors.
---
Nitpick comments:
In `@packages/web/src/app/api/`(server)/ee/mcp/route.ts:
- Line 115: The MCP route is enforcing a hardcoded 'mcp' OAuth scope instead of
the canonical SOURCEBOT_MCP_OAUTH_SCOPE constant, which can drift from the
advertised challenge scope. Update the requiredOAuthScopes configuration in the
MCP route handler to use SOURCEBOT_MCP_OAUTH_SCOPE everywhere the scope is
enforced, including the other matching location in this file, so the challenge
and route stay aligned.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6cd0d0ab-85c8-4807-b647-11fec66e2cb5
📒 Files selected for processing (4)
packages/web/src/app/api/(server)/ee/mcp/route.tspackages/web/src/ee/features/oauth/constants.tspackages/web/src/ee/features/oauth/server.tspackages/web/src/middleware/withAuth.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/web/src/ee/features/oauth/constants.ts
- packages/web/src/middleware/withAuth.ts
…n-in-resource-server
…n-in-resource-server
License Audit❌ Status: FAIL
Fail Reasons
Unresolved Packages
Weak Copyleft Packages (informational)
Resolved Packages (17)
|
Add the groundwork for validating OAuth scopes per endpoint.