Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.praison.ai/llms.txt

Use this file to discover all available pages before exploring further.

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 RoleNotes
GET /workspaces/{id}member
PATCH /workspaces/{id}admin
DELETE /workspaces/{id}owner
GET /workspaces/{id}/membersmember
POST /workspaces/{id}/membersadminExtra check: owner required for admin/owner roles
PATCH /workspaces/{id}/members/{user_id}admin
DELETE /workspaces/{id}/members/{user_id}admin

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

Breaking Change: If you have an existing client that mutates workspaces, members, agents, or issues as a non-admin member, those calls now return 403. Grant the calling user the admin (or owner where required) role first.

Owner-only Sub-checks

Beyond the base role requirements, certain operations require additional owner privileges:

Member Management with Owner Role

OperationRequirementError Message
Add member with role=ownerCaller must be ownerOnly owners can add another owner
Change role to ownerCaller must be ownerOnly owners can assign the owner role
Change existing owner roleCaller must be ownerOnly owners can change an owner's role
Remove existing ownerCaller must be ownerOnly owners can remove an owner
Change your own roleAlways forbiddenCannot change your own role
Remove yourselfAlways forbiddenCannot remove yourself from the workspace

Example Owner-only Operations

# These operations require the caller to be an owner:
POST /workspaces/{id}/members {"user_id": "user-123", "role": "owner"}
PATCH /workspaces/{id}/members/user-456 {"role": "owner"}  
PATCH /workspaces/{id}/members/owner-789 {"role": "admin"}
DELETE /workspaces/{id}/members/owner-789

# These are always forbidden regardless of role:
PATCH /workspaces/{id}/members/your-user-id {"role": "member"}  # Self role change
DELETE /workspaces/{id}/members/your-user-id                   # Self removal

Cross-workspace Access (IDOR)

The ensure_resource_in_workspace function prevents cross-workspace resource access by returning 404 (not 403) when a resource exists but belongs to a different workspace.

Protected Resources

ResourceRoutes404 Message
AgentsGET/PATCH/DELETE /agents/{id}Agent not found
IssuesGET/PATCH/DELETE /issues/{id}Issue not found
Issue CommentsPOST/GET /issues/{id}/commentsIssue not found
This prevents enumeration of resource IDs across workspaces by making cross-workspace resources appear non-existent.

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
}

403 Forbidden - Owner Role Required

When an admin attempts to assign admin or owner roles:
{
  "detail": "Only owners can assign admin or owner roles",
  "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 batch 3After batch 3
Valid user, non-member✅ Access granted❌ 403 Forbidden
Valid user, workspace member✅ Access granted✅ Access granted
Invalid token❌ 401 Unauthorized❌ 401 Unauthorized
Admin promotes member → admin✅ allowed❌ 403 Forbidden
Admin promotes member → owner❌ already blocked❌ still blocked
Owner promotes member → admin✅ allowed✅ allowed
Cross-workspace resource access via service layerSurface IDOR risk❌ returns None/404

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