Skip to content

[FEATURE][AUTH]: Add A2A agent RBAC enforcement to token scoping middleware #2389

@crivetimihai

Description

@crivetimihai

🔐 Feature: Add A2A Agent RBAC Enforcement to Token Scoping Middleware

Goal

Add A2A agent RBAC enforcement to the token scoping middleware so that A2A agents follow the same visibility model (public/team/private) as other resources, ensuring consistent access control across all entity types.

Why Now?

  1. Security Gap: A2A agents can be created and accessed without team-based visibility checks, creating an inconsistent security posture
  2. RBAC Completeness: All other major entities (servers, tools, resources, prompts, gateways) have RBAC enforcement; A2A agents are the missing piece
  3. Multi-Tenant Requirements: Organizations deploying multi-tenant configurations need A2A agents isolated by team
  4. Compliance: Audit requirements demand consistent access control across all API resources

📖 User Stories

US-1: Admin - Restrict A2A Agent Access by Team

As a Platform Administrator
I want A2A agents to respect team-based visibility rules
So that agents created by one team are not accessible by other teams

Acceptance Criteria:

Scenario: Team-scoped token accessing team's A2A agent
  Given a user with a token scoped to team "engineering"
  And an A2A agent "code-reviewer" with visibility "team" belonging to team "engineering"
  When the user requests GET /a2a/{agent_id}
  Then the request should succeed with status 200
  And the agent details should be returned

Scenario: Team-scoped token denied access to other team's agent
  Given a user with a token scoped to team "engineering"
  And an A2A agent "hr-assistant" with visibility "team" belonging to team "hr"
  When the user requests GET /a2a/{agent_id}
  Then the request should fail with status 403
  And the error should be "Access denied: You do not have permission to access this resource"

Scenario: Public A2A agent accessible by all authenticated users
  Given a user with any valid token
  And an A2A agent "public-helper" with visibility "public"
  When the user requests GET /a2a/{agent_id}
  Then the request should succeed with status 200

Technical Requirements:

  • Add A2A agent pattern to _RESOURCE_PATTERNS in token_scoping.py
  • Query A2AAgent.visibility and A2AAgent.team_id in _check_resource_team_ownership
  • Log access decisions for audit trail
US-2: Developer - A2A Agent CRUD Permission Enforcement

As a Developer using the API
I want A2A agent CRUD operations to require appropriate permissions
So that only authorized users can create, update, or delete agents

Acceptance Criteria:

Scenario: Create A2A agent requires agents.create permission
  Given a user with a token that has permission "agents.read" only
  When the user requests POST /a2a with a new agent payload
  Then the request should fail with status 403
  And the error should be "Insufficient permissions for this operation"

Scenario: Delete A2A agent requires agents.delete permission
  Given a user with a token that has permission "agents.delete"
  And an A2A agent the user owns
  When the user requests DELETE /a2a/{agent_id}
  Then the request should succeed with status 200

Scenario: Update A2A agent requires agents.update permission
  Given a user with a token that has permission "agents.update"
  And an A2A agent belonging to user's team
  When the user requests PUT /a2a/{agent_id}
  Then the request should succeed with status 200

Technical Requirements:

  • Add AGENTS_CREATE, AGENTS_READ, AGENTS_UPDATE, AGENTS_DELETE to Permissions class
  • Add A2A permission patterns to _PERMISSION_PATTERNS in token_scoping.py
  • Map HTTP methods to required permissions
US-3: Security Auditor - A2A Access Audit Trail

As a Security Auditor
I want all A2A agent access attempts logged
So that I can review who accessed which agents and when

Acceptance Criteria:

Scenario: Successful A2A access is logged
  Given audit logging is enabled
  When a user successfully accesses an A2A agent
  Then a log entry should contain:
    | Field | Value |
    | resource_type | a2a_agent |
    | resource_id | {agent_id} |
    | decision | ALLOW |
    | user_email | {user_email} |

Scenario: Denied A2A access is logged
  Given audit logging is enabled
  When a user is denied access to an A2A agent
  Then a log entry should contain:
    | Field | Value |
    | resource_type | a2a_agent |
    | decision | DENY |
    | reason | team visibility mismatch |

🏗 Architecture

Token Scoping Flow for A2A Agents

sequenceDiagram
    participant Client
    participant Middleware as TokenScopingMiddleware
    participant DB as Database
    participant API as A2A API

    Client->>Middleware: GET /a2a/{agent_id}
    Middleware->>Middleware: Extract JWT payload
    Middleware->>Middleware: Extract agent_id from path
    
    alt Permission Check
        Middleware->>Middleware: Check agents.read in permissions
        Note over Middleware: Uses _PERMISSION_PATTERNS
    end
    
    alt Visibility Check
        Middleware->>DB: SELECT visibility, team_id FROM a2a_agents WHERE id = ?
        DB-->>Middleware: {visibility: "team", team_id: "eng-123"}
        
        alt visibility == "public"
            Middleware->>API: Allow access
        else visibility == "team"
            Middleware->>Middleware: Check agent.team_id in token_teams
            alt Team match
                Middleware->>API: Allow access
            else No match
                Middleware-->>Client: 403 Forbidden
            end
        else visibility == "private"
            Middleware->>Middleware: Check agent.owner_email == user_email
        end
    end
    
    API-->>Client: A2A Agent Response
Loading

Code Changes

# mcpgateway/db.py - Add to Permissions class
class Permissions:
    # ... existing permissions ...
    
    # A2A Agent permissions
    AGENTS_CREATE = "agents.create"
    AGENTS_READ = "agents.read"
    AGENTS_UPDATE = "agents.update"
    AGENTS_DELETE = "agents.delete"
    AGENTS_INVOKE = "agents.invoke"


# mcpgateway/middleware/token_scoping.py - Add patterns
_RESOURCE_PATTERNS: List[Tuple[Pattern[str], str]] = [
    # ... existing patterns ...
    (re.compile(r"/a2a/?([a-f0-9\-]+)"), "a2a_agent"),
]

_PERMISSION_PATTERNS: List[Tuple[str, Pattern[str], str]] = [
    # ... existing patterns ...
    # A2A Agent permissions
    ("GET", re.compile(r"^/a2a(?:$|/)"), Permissions.AGENTS_READ),
    ("POST", re.compile(r"^/a2a(?:$|/)"), Permissions.AGENTS_CREATE),
    ("PUT", re.compile(r"^/a2a/[^/]+(?:$|/)"), Permissions.AGENTS_UPDATE),
    ("DELETE", re.compile(r"^/a2a/[^/]+(?:$|/)"), Permissions.AGENTS_DELETE),
]

📋 Implementation Tasks

Phase 1: Permission Constants

  • Add AGENTS_CREATE, AGENTS_READ, AGENTS_UPDATE, AGENTS_DELETE, AGENTS_INVOKE to Permissions class in db.py
  • Update get_all_permissions() to include new agent permissions
  • Add agent permissions to default roles in bootstrap_db.py

Phase 2: Token Scoping Patterns

  • Add A2A agent pattern (re.compile(r"/a2a/?([a-f0-9\-]+)"), "a2a_agent") to _RESOURCE_PATTERNS
  • Add A2A permission patterns to _PERMISSION_PATTERNS for GET/POST/PUT/DELETE
  • Handle /a2a/{id}/invoke endpoint with AGENTS_INVOKE permission

Phase 3: Visibility Enforcement

  • Add resource_type == "a2a_agent" branch in _check_resource_team_ownership
  • Query A2AAgent model for visibility and team_id
  • Apply public/team/private visibility logic matching other resources
  • Handle owner_email check for private visibility

Phase 4: Testing

  • Unit tests for A2A pattern extraction from paths
  • Unit tests for permission mapping
  • Integration tests for team-scoped A2A access
  • Integration tests for public A2A access
  • Integration tests for permission enforcement on CRUD operations
  • Test denied access logging

Phase 5: Documentation

  • Update RBAC documentation with A2A agent section
  • Document agent permissions in API docs
  • Add examples to todo/rbac.md

⚙️ Configuration Example

No new configuration required. A2A agents use existing visibility field:

{
  "name": "Code Review Agent",
  "endpoint_url": "https://agent.example.com/v1",
  "visibility": "team",
  "team_id": "eng-123",
  "owner_email": "dev@example.com"
}

✅ Success Criteria

  • A2A agents with visibility: team only accessible by team members
  • A2A agents with visibility: public accessible by all authenticated users
  • A2A agents with visibility: private only accessible by owner
  • CRUD operations require appropriate agents.* permissions
  • All access attempts logged for audit
  • No regression in existing RBAC functionality
  • Unit test coverage > 90% for new code
  • Integration tests pass for all visibility scenarios

🏁 Definition of Done

  • Permission constants added to Permissions class
  • Token scoping patterns added for A2A paths
  • Visibility checks implemented in _check_resource_team_ownership
  • Unit tests written and passing
  • Integration tests written and passing
  • Code passes make verify
  • RBAC documentation updated
  • PR reviewed and approved

🧩 Affected Components

  • mcpgateway/db.py - Permissions class
  • mcpgateway/middleware/token_scoping.py - Pattern matching and visibility checks
  • mcpgateway/bootstrap_db.py - Default role permissions
  • tests/ - Unit and integration tests

🔗 Related Issues

Metadata

Metadata

Assignees

Labels

MUSTP1: Non-negotiable, critical requirements without which the product is non-functional or unsafea2aSupport for A2A protocolenhancementNew feature or requesticaICA related issuespythonPython / backend development (FastAPI)rbacRole-based Access ControlreadyValidated, ready-to-work-on itemssecurityImproves security

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions