Skip to content

Conversation

@vibegui
Copy link
Contributor

@vibegui vibegui commented Jan 3, 2026

Previously, mesh JWT tokens and API keys didn't include the user's organization role, preventing admin/owner bypass in access control. This adds role lookup from the member table for both auth methods.

What is this contribution about?

Describe your changes and why they're needed.

Screenshots/Demonstration

Add screenshots or a Loom video if your changes affect the UI.

Review Checklist

  • PR title is clear and descriptive
  • Changes are tested and working
  • Documentation is updated (if needed)
  • No breaking changes

Summary by cubic

Fixes missing organization role in auth for mesh JWTs and API keys. We now look up member.role by userId and attach it to user in the request context, so admin/owner bypass works.

Written for commit b1a752e. Summary will update on new commits.


Note

Adds role resolution to Bearer-token auth paths.

  • For verified Mesh JWTs and API keys, query member.role (by userId + organization) and set user.role in the returned auth context
  • Keeps existing permission handling; organization still sourced from token/metadata
  • Enables built-in role bypass in AccessControl via populated role

Written by Cursor Bugbot for commit de852d5. This will update automatically on new commits. Configure here.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 3, 2026

🧪 Benchmark

Should we run the MCP Gateway benchmark for this PR?

React with 👍 to run the benchmark.

Reaction Action
👍 Run quick benchmark (10 & 128 tools)

Benchmark will run on the next push after you react.

@github-actions
Copy link
Contributor

github-actions bot commented Jan 3, 2026

Release Options

Should a new version be published when this PR is merged?

React with an emoji to vote on the release type:

Reaction Type Next Version
👍 Prerelease 1.0.18-alpha.1
🎉 Patch 1.0.18
❤️ Minor 1.1.0
🚀 Major 2.0.0

Current version: 1.0.17

Deployment

  • Deploy to production (triggers ArgoCD sync after Docker image is published)

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="apps/mesh/src/core/context-factory.ts">

<violation number="1" location="apps/mesh/src/core/context-factory.ts:478">
P1: Role lookup query doesn&#39;t filter by organization. A user with memberships in multiple organizations could get the wrong role (e.g., &#39;member&#39; role from Org A instead of &#39;owner&#39; from Org B), breaking the admin/owner bypass. Add `.where(&quot;member.organizationId&quot;, &quot;=&quot;, meshJwtPayload.metadata?.organizationId)` to scope the query.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

// Look up user's organization role for admin/owner bypass
let role: string | undefined;
if (meshJwtPayload.sub) {
const membership = await db
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Jan 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Role lookup query doesn't filter by organization. A user with memberships in multiple organizations could get the wrong role (e.g., 'member' role from Org A instead of 'owner' from Org B), breaking the admin/owner bypass. Add .where("member.organizationId", "=", meshJwtPayload.metadata?.organizationId) to scope the query.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/mesh/src/core/context-factory.ts, line 478:

<comment>Role lookup query doesn&#39;t filter by organization. A user with memberships in multiple organizations could get the wrong role (e.g., &#39;member&#39; role from Org A instead of &#39;owner&#39; from Org B), breaking the admin/owner bypass. Add `.where(&quot;member.organizationId&quot;, &quot;=&quot;, meshJwtPayload.metadata?.organizationId)` to scope the query.</comment>

<file context>
@@ -472,10 +472,22 @@ async function authenticateRequest(
+        // Look up user&#39;s organization role for admin/owner bypass
+        let role: string | undefined;
+        if (meshJwtPayload.sub) {
+          const membership = await db
+            .selectFrom(&quot;member&quot;)
+            .select([&quot;member.role&quot;])
</file context>

✅ Addressed in de852d5

Previously, mesh JWT tokens and API keys didn't include the user's
organization role, preventing admin/owner bypass in access control.
This adds role lookup from the member table for both auth methods.
@viktormarinho viktormarinho force-pushed the fix/mesh-jwt-role-lookup branch from af54a44 to c7eee6d Compare January 5, 2026 18:35
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is being reviewed by Cursor Bugbot

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

.select(["member.role"])
.where("member.userId", "=", meshJwtPayload.sub)
.executeTakeFirst();
role = membership?.role;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DB error in role lookup silently fails valid authentication

The new database queries for role lookup are placed inside try blocks designed only for JWT/API key validation errors. If the database query throws (connection error, timeout, etc.), the exception is caught by the outer catch block, causing valid authentication to silently fail. For Mesh JWT, there's no logging at all - the code just proceeds to try API key authentication. For API keys, the error is logged with a misleading message. A transient database error would cause authenticated users to unexpectedly lose access.

Additional Locations (1)

Fix in Cursor Fix in Web

user: {
id: meshJwtPayload.sub,
connectionId: meshJwtPayload.metadata?.connectionId,
role,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing top-level role breaks bypass in two code paths

The PR adds role to the user object for Mesh JWT and API key authentication, but fails to also set the top-level role property in the return object. Session auth correctly returns both user.role AND a top-level role. However, the top-level role is what's used by createBoundAuthClient (line 674) and the main AccessControl instance (line 705) for the built-in role bypass. Since authResult.role will be undefined for Mesh JWT and API key auth, the admin/owner bypass won't work in boundAuth.hasPermission() or the default access instance—only the proxy-specific AccessControl instances that use ctx.auth.user?.role will correctly bypass.

Additional Locations (1)

Fix in Cursor Fix in Web

@vibegui vibegui merged commit 9aac573 into main Jan 5, 2026
5 checks passed
@vibegui vibegui deleted the fix/mesh-jwt-role-lookup branch January 5, 2026 21:13
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.

4 participants