Skip to main content
API Route RBAC Enforcement protects workspace-scoped resources by requiring valid membership before allowing access to any workspace endpoints.

Quick Start

1

Protected Route Access

from praisonai_platform.client import PlatformClient

# All workspace routes now require membership
client = PlatformClient("http://localhost:8000", token="your-jwt-token")

# This will only succeed if you're a member of the workspace
projects = await client.list_projects("ws-abc123")
2

Membership Validation

from praisonai_platform.api.deps import require_workspace_member
from fastapi import Depends

# FastAPI route with RBAC enforcement
@router.get("/{workspace_id}/projects/")
async def list_projects(
    workspace_id: str,
    user: AuthIdentity = Depends(require_workspace_member),  # ← RBAC enforcement
    session: AsyncSession = Depends(get_db),
):
    # User is guaranteed to be a workspace member here
    project_service = ProjectService(session)
    return await project_service.list_for_workspace(workspace_id)
3

Role-based Access Control

from praisonai_platform.api.deps import require_workspace_member
from functools import partial

# Require admin role or higher
require_admin = partial(require_workspace_member, min_role="admin")

@router.delete("/{workspace_id}/projects/{project_id}")
async def delete_project(
    workspace_id: str,
    project_id: str,
    user: AuthIdentity = Depends(require_admin),  # ← Admin required
    session: AsyncSession = Depends(get_db),
):
    # User has admin privileges in this workspace
    pass

How It Works

ComponentResponsibility
require_workspace_memberFastAPI dependency that enforces workspace membership
MemberService.has_role()Database query to verify user’s workspace membership and role
AuthIdentityEnhanced with workspace_id for downstream route handlers
403 ForbiddenReturned to non-members attempting workspace access

Implementation Details

RBAC Dependency

The require_workspace_member dependency replaces get_current_user in all workspace-scoped routes:
# Before (GAP-8): Only authentication
@router.get("/{workspace_id}/projects/")
async def list_projects(
    workspace_id: str,
    user: AuthIdentity = Depends(get_current_user),  # ← Only checks valid token
    session: AsyncSession = Depends(get_db),
):
    pass

# After (GAP-8): Authentication + Authorization
@router.get("/{workspace_id}/projects/")
async def list_projects(
    workspace_id: str,
    user: AuthIdentity = Depends(require_workspace_member),  # ← Checks membership
    session: AsyncSession = Depends(get_db),
):
    # user.workspace_id is now available
    pass

Dependency Configuration

from praisonai_platform.api.deps import require_workspace_member
from functools import partial

# Default: requires "member" role or higher
require_member = require_workspace_member

# Custom: require "admin" role or higher
require_admin = partial(require_workspace_member, min_role="admin")

# Custom: require "owner" role
require_owner = partial(require_workspace_member, min_role="owner")

Role Hierarchy


Protected Routes

All workspace-scoped API routes now enforce membership:

Core Resources

Route PatternEnforcementMinimum Role
GET /workspaces/{id}member
PATCH /workspaces/{id}admin
DELETE /workspaces/{id}owner
GET /workspaces/{id}/membersmember
POST /workspaces/{id}/membersadmin

Project Management

Route PatternEnforcementMinimum Role
GET /workspaces/{id}/projects/member
POST /workspaces/{id}/projects/member
PATCH /workspaces/{id}/projects/{pid}member
DELETE /workspaces/{id}/projects/{pid}admin

Issue Tracking

Route PatternEnforcementMinimum Role
GET /workspaces/{id}/issues/member
POST /workspaces/{id}/issues/member
GET /workspaces/{id}/issues/{iid}member
PATCH /workspaces/{id}/issues/{iid}member
DELETE /workspaces/{id}/issues/{iid}admin

Agent Management

Route PatternEnforcementMinimum Role
GET /workspaces/{id}/agents/member
POST /workspaces/{id}/agents/member
PATCH /workspaces/{id}/agents/{aid}member
DELETE /workspaces/{id}/agents/{aid}admin

Error Responses

403 Forbidden - Non-Member

When a valid user attempts to access a workspace they’re not a member of:
{
  "detail": "User is not a member of this workspace",
  "status_code": 403
}

403 Forbidden - Insufficient Role

When a member lacks the required role level:
{
  "detail": "Insufficient permissions. Requires admin role or higher",
  "status_code": 403
}

401 Unauthorized

When authentication fails (invalid/missing token):
{
  "detail": "Invalid or expired token",
  "status_code": 401
}

API Testing

Valid Member Access

# Member accessing their workspace (✅ Success)
curl -H "Authorization: Bearer $MEMBER_TOKEN" \
  http://localhost:8000/api/v1/workspaces/ws-abc123/projects/

# Response: 200 OK with project list

Non-Member Access

# Non-member attempting access (❌ Forbidden)
curl -H "Authorization: Bearer $OTHER_USER_TOKEN" \
  http://localhost:8000/api/v1/workspaces/ws-abc123/projects/

# Response: 403 Forbidden

Role-based Access

# Member trying admin action (❌ Forbidden)
curl -X DELETE -H "Authorization: Bearer $MEMBER_TOKEN" \
  http://localhost:8000/api/v1/workspaces/ws-abc123/projects/proj-123

# Response: 403 Forbidden (requires admin)

# Admin performing same action (✅ Success)
curl -X DELETE -H "Authorization: Bearer $ADMIN_TOKEN" \
  http://localhost:8000/api/v1/workspaces/ws-abc123/projects/proj-123

# Response: 204 No Content

Migration Impact

Behavior Changes

ScenarioBefore GAP-8After GAP-8
Valid user, non-member✅ Access granted❌ 403 Forbidden
Valid user, workspace member✅ Access granted✅ Access granted
Invalid token❌ 401 Unauthorized❌ 401 Unauthorized

Client Impact

# SDK automatically handles the new authorization requirements
from praisonai_platform.client import PlatformClient

# This client request will now fail if user is not a workspace member
client = PlatformClient("http://localhost:8000", token="user-token")

try:
    projects = await client.list_projects("ws-abc123")
    print("Access granted - user is a member")
except Exception as e:
    print(f"Access denied: {e}")
    # Handle 403 Forbidden appropriately

Best Practices

Always handle 403 Forbidden responses in client applications. Display user-friendly messages when workspace access is denied rather than generic error messages.
Configure route dependencies with the minimum required role. Don’t require admin for operations that member can safely perform.
Check user workspace membership before displaying UI elements like “Create Project” buttons to prevent unsuccessful API calls.
Log and monitor 403 responses to identify potential security issues or UX problems with workspace access patterns.

Testing

Verify RBAC enforcement with the integration test suite:
# Run RBAC enforcement tests
pytest tests/test_new_api_integration.py::TestRBACEnforcement -v

# Run specific workspace access tests
pytest tests/test_new_api_integration.py -k "test_workspace_member" -v
Expected test scenarios:
  • Non-member 403 responses on all workspace routes
  • Member access granted for basic operations
  • Admin role enforcement for management operations
  • Owner role enforcement for destructive operations

Team Members & RBAC

Learn about workspace member management

Authentication

Understand JWT token authentication