Workspace membership enforcement on all API routes with require_workspace_member dependency
API Route RBAC Enforcement protects workspace-scoped resources by requiring valid membership before allowing access to any workspace endpoints.API Route RBAC Enforcement protects workspace-scoped resources by requiring valid membership before allowing access to any workspace endpoints.
from praisonaiagents import Agentagent = Agent(name="security-bot", instructions="Respect workspace RBAC on API routes.")agent.start("Can this token delete issues in workspace WS-1?")
The user calls workspace-scoped routes; middleware checks membership and role before any mutation runs.
from praisonai_platform.client import PlatformClient# All workspace routes now require membershipclient = PlatformClient("http://localhost:8000", token="your-jwt-token")# This will only succeed if you're a member of the workspaceprojects = await client.list_projects("ws-abc123")
2
Membership Validation
from praisonai_platform.api.deps import require_workspace_memberfrom 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_memberfrom functools import partial# Require admin role or higherrequire_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
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.
# 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 changeDELETE /workspaces/{id}/members/your-user-id # Self removal
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.
# 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
# SDK automatically handles the new authorization requirementsfrom praisonai_platform.client import PlatformClient# This client request will now fail if user is not a workspace memberclient = 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
Always handle 403 Forbidden responses in client applications. Display user-friendly messages when workspace access is denied rather than generic error messages.
Use Appropriate Role Requirements
Configure route dependencies with the minimum required role. Don’t require admin for operations that member can safely perform.
Validate Membership Before UI Actions
Check user workspace membership before displaying UI elements like “Create Project” buttons to prevent unsuccessful API calls.
Monitor Failed Authorization Attempts
Log and monitor 403 responses to identify potential security issues or UX problems with workspace access patterns.