Back to Blog
4 min read

Item Permissions in Fabric: Granular Access Control

While workspace roles provide broad access, item permissions enable granular control over specific artifacts. Today, I will cover how to implement fine-grained access control in Fabric.

Item Permissions Overview

Item permissions allow access to specific items independent of workspace membership:

item_permission_types = {
    "read": {
        "description": "View item and its data",
        "includes": ["View", "Query data", "Use in reports"]
    },
    "write": {
        "description": "Modify the item",
        "includes": ["Edit", "Save changes"]
    },
    "reshare": {
        "description": "Share with others",
        "includes": ["Grant permissions", "Share links"]
    },
    "build": {
        "description": "Build new content (semantic models)",
        "includes": ["Create reports", "Use as data source"]
    }
}

Sharing Items

import requests

def share_item(
    workspace_id: str,
    item_id: str,
    recipient_email: str,
    permissions: list,
    headers: dict
):
    """Share item with specific permissions"""

    url = f"https://api.fabric.microsoft.com/v1/workspaces/{workspace_id}/items/{item_id}/share"

    payload = {
        "recipients": [
            {
                "userPrincipalName": recipient_email
            }
        ],
        "permissions": permissions  # ["Read", "Write", "Reshare"]
    }

    response = requests.post(url, headers=headers, json=payload)
    return response.json()

# Share semantic model with build permission
share_item(
    workspace_id="ws-guid",
    item_id="semantic-model-guid",
    recipient_email="analyst@company.com",
    permissions=["Read", "Build"],
    headers=headers
)

Permission Inheritance

┌─────────────────────────────────────────────────────┐
│            Permission Inheritance                    │
├─────────────────────────────────────────────────────┤
│                                                      │
│  Workspace Role                                     │
│       │                                             │
│       ▼                                             │
│  ┌─────────────┐      ┌─────────────┐              │
│  │ Lakehouse   │──────│ Tables      │              │
│  │ (workspace  │      │ (inherits)  │              │
│  │  access)    │      │             │              │
│  └─────────────┘      └─────────────┘              │
│                                                      │
│  Item Permission                                    │
│       │                                             │
│       ▼                                             │
│  ┌─────────────┐      ┌─────────────┐              │
│  │ Semantic    │──────│ Reports     │              │
│  │ Model       │      │ (can be     │              │
│  │ (shared)    │      │  shared     │              │
│  │             │      │  separately)│              │
│  └─────────────┘      └─────────────┘              │
│                                                      │
│  Note: Data access flows through semantic model    │
│  RLS applies regardless of item permissions        │
│                                                      │
└─────────────────────────────────────────────────────┘

Managing Item Permissions via API

class ItemPermissionManager:
    def __init__(self, headers: dict):
        self.headers = headers
        self.base_url = "https://api.fabric.microsoft.com/v1"

    def get_item_permissions(self, workspace_id: str, item_id: str) -> list:
        """Get all permissions for an item"""
        url = f"{self.base_url}/workspaces/{workspace_id}/items/{item_id}/permissions"
        response = requests.get(url, headers=self.headers)
        return response.json().get("value", [])

    def grant_permission(
        self,
        workspace_id: str,
        item_id: str,
        principal_type: str,  # User, Group, ServicePrincipal
        principal_id: str,
        permissions: list
    ) -> dict:
        """Grant permissions to a principal"""
        url = f"{self.base_url}/workspaces/{workspace_id}/items/{item_id}/permissions"

        payload = {
            "principal": {
                "type": principal_type,
                "id": principal_id
            },
            "permissions": permissions
        }

        response = requests.post(url, headers=self.headers, json=payload)
        return response.json()

    def revoke_permission(
        self,
        workspace_id: str,
        item_id: str,
        principal_id: str
    ) -> bool:
        """Revoke all permissions for a principal"""
        url = f"{self.base_url}/workspaces/{workspace_id}/items/{item_id}/permissions/{principal_id}"
        response = requests.delete(url, headers=self.headers)
        return response.status_code == 200

    def update_permission(
        self,
        workspace_id: str,
        item_id: str,
        principal_id: str,
        new_permissions: list
    ) -> dict:
        """Update permissions for a principal"""
        url = f"{self.base_url}/workspaces/{workspace_id}/items/{item_id}/permissions/{principal_id}"

        payload = {
            "permissions": new_permissions
        }

        response = requests.patch(url, headers=self.headers, json=payload)
        return response.json()

# Usage
manager = ItemPermissionManager(headers)

# Grant read access to a report
manager.grant_permission(
    workspace_id="ws-guid",
    item_id="report-guid",
    principal_type="User",
    principal_id="user@company.com",
    permissions=["Read"]
)

# Grant build permission on semantic model
manager.grant_permission(
    workspace_id="ws-guid",
    item_id="semantic-model-guid",
    principal_type="Group",
    principal_id="azure-ad-group-guid",
    permissions=["Read", "Build"]
)

Common Sharing Scenarios

sharing_scenarios = {
    "report_to_executives": {
        "item_type": "Report",
        "permissions": ["Read"],
        "description": "View-only access to finished report",
        "rls": "May apply based on semantic model"
    },
    "semantic_model_to_analysts": {
        "item_type": "Semantic Model",
        "permissions": ["Read", "Build"],
        "description": "Analysts can create their own reports",
        "rls": "Applies to all reports built on model"
    },
    "lakehouse_to_data_engineers": {
        "item_type": "Lakehouse",
        "permissions": ["Read", "Write"],
        "description": "Engineers can read and write data",
        "note": "Usually via workspace role instead"
    },
    "pipeline_to_operations": {
        "item_type": "Pipeline",
        "permissions": ["Read"],
        "description": "Ops can monitor but not modify",
        "note": "Cannot execute without workspace access"
    }
}

Bulk Permission Management

def bulk_grant_permissions(
    manager: ItemPermissionManager,
    workspace_id: str,
    item_ids: list,
    principals: list,
    permissions: list
):
    """Grant same permissions across multiple items"""

    results = []
    for item_id in item_ids:
        for principal in principals:
            result = manager.grant_permission(
                workspace_id=workspace_id,
                item_id=item_id,
                principal_type=principal["type"],
                principal_id=principal["id"],
                permissions=permissions
            )
            results.append({
                "item_id": item_id,
                "principal": principal["id"],
                "success": "error" not in result
            })

    return results

# Share multiple reports with a group
reports = ["report-1-guid", "report-2-guid", "report-3-guid"]
principals = [{"type": "Group", "id": "sales-team-group-guid"}]

results = bulk_grant_permissions(
    manager=manager,
    workspace_id="ws-guid",
    item_ids=reports,
    principals=principals,
    permissions=["Read"]
)

Permission Auditing

def audit_item_permissions(manager: ItemPermissionManager, workspace_id: str, item_id: str):
    """Audit permissions for an item"""

    permissions = manager.get_item_permissions(workspace_id, item_id)

    audit_report = {
        "item_id": item_id,
        "audit_date": datetime.now().isoformat(),
        "total_permissions": len(permissions),
        "by_type": {"User": 0, "Group": 0, "ServicePrincipal": 0},
        "by_permission": {"Read": 0, "Write": 0, "Reshare": 0, "Build": 0},
        "details": []
    }

    for perm in permissions:
        principal_type = perm.get("principal", {}).get("type")
        audit_report["by_type"][principal_type] = audit_report["by_type"].get(principal_type, 0) + 1

        for p in perm.get("permissions", []):
            audit_report["by_permission"][p] = audit_report["by_permission"].get(p, 0) + 1

        audit_report["details"].append({
            "principal": perm.get("principal", {}).get("displayName"),
            "type": principal_type,
            "permissions": perm.get("permissions")
        })

    return audit_report

Item permissions provide the flexibility to share specific artifacts securely. Tomorrow, I will cover Row-Level Security in Fabric.

Resources

Michael John Peña

Michael John Peña

Senior Data Engineer based in Sydney. Writing about data, cloud, and technology.