Hi all, I’m trying to set up a service principal to use the Power BI REST APIs, but I keep running into 401 Unauthorized errors. Here’s what I’ve done so far: Created an App Registration in Entra ID (Azure AD). Created a client secret and stored the secret, client ID, and tenant ID. Under API permissions → Power BI Service (Application), I added: Tenant.ReadWrite.All Tenant.Read.All Granted Admin Consent. In the Power BI Admin Portal: Enabled “Allow service principals to use Power BI APIs” (set to Entire Organization). Gave the service principal Admin access in the Admin portal. Added the service principal to a Power BI workspace with Admin role. When I request a token using the client ID/secret/tenant ID and call an endpoint like: GET https://api.powerbi.com/v1.0/myorg/groups → I always get 401 Unauthorized. Testing Code Here’s the Python code I’m using to verify permissions and try triggering a dataset refresh (simplified for clarity): def get_token(tenant_id, client_id, client_secret, scope): """ Get Azure AD access token using client credentials flow. """ try: logging.info(f"Requesting token for scope: {scope}") resp = requests.post( f"https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token", data={ "client_id": client_id, "client_secret": client_secret, "grant_type": "client_credentials", "scope": scope }, timeout=30 ) resp.raise_for_status() token = resp.json().get("access_token") print("✅ Token retrieved successfully") logging.info("✅ Token retrieved successfully") return token except Exception as e: print("✅ Token retrieved successfully") logging.error(f"❌ Failed to get token: {e}") raise def check_powerbi_permissions(token, group_id, dataset_id😞 """ Check if the service principal has access to the Power BI workspace and dataset. Args: token (str): Power BI access token group_id (str): Power BI workspace ID dataset_id (str): Power BI dataset ID """ headers = {"Authorization": f"Bearer {token}","Content-Type": "application/json"} try: # 1. List workspaces the SP has access to url_groups = "https://api.powerbi.com/v1.0/myorg/groups" resp_groups = requests.get(url_groups, headers=headers, timeout=30) if resp_groups.status_code == 401: logging.error("❌ Unauthorized: Service principal may not be enabled for Power BI API.") print(f"❌ Unauthorized: Service principal may not be enabled for Power BI API.") logging.error("➡️ Check Admin portal: enable 'Service principals can use Power BI APIs'.") print(f"➡️ Check Admin portal: enable 'Service principals can use Power BI APIs'.") return False resp_groups.raise_for_status() groups = resp_groups.json().get("value", []) logging.info(f"✅ Workspaces retrieved: {[g['id'] for g in groups]}") print(f"✅ Workspaces retrieved: {[g['id'] for g in groups]}") if not any(g["id"] == group_id for g in groups): logging.error(f"❌ Service principal does not have access to workspace {group_id}") print(f"❌ Service principal does not have access to workspace {group_id}") return False logging.info(f"✅ Service principal has access to workspace {group_id}") print(f"✅ Service principal has access to workspace {group_id}") # 2. List datasets inside the workspace url_datasets = f"https://api.powerbi.com/v1.0/myorg/groups/{group_id}/datasets" resp_datasets = requests.get(url_datasets, headers=headers, timeout=30) resp_datasets.raise_for_status() datasets = resp_datasets.json().get("value", []) logging.info(f"✅ Datasets in workspace {group_id}: {[d['id'] for d in datasets]}") print(f"✅ Datasets in workspace {group_id}: {[d['id'] for d in datasets]}") if not any(d["id"] == dataset_id for d in datasets): logging.error(f"❌ Service principal does not have access to dataset {dataset_id}") print(f"❌ Service principal does not have access to dataset {dataset_id}") return False logging.info(f"✅ Service principal has access to dataset {dataset_id}") print(f"✅ Service principal has access to dataset {dataset_id}") return True except Exception as e: logging.error(f"❌ Failed to check Power BI permissions: {e}") print(f"❌ Failed to check Power BI permissions: {e}") return False pbi_token = get_token(TENANT_ID, CLIENT_ID, CLIENT_SECRET, "https://analysis.windows.net/powerbi/api/.default") if check_powerbi_permissions(pbi_token, GROUP_ID, DATASET_ID): print('success') else: print("🚨 Service principal does not have required access. Fix permissions before retrying.") Full code includes helper functions for: Getting a token (client_credentials flow) Checking workspace/dataset access Triggering a dataset refresh Polling refresh status Cancelling refresh if needed Questions: Am I missing additional Application permissions such as Dataset.ReadWrite.All, Workspace.Read.All, or Report.ReadWrite.All? Should these permissions appear in the decoded JWT token under "roles"? Since the SP is already in a workspace and tenant settings are enabled org-wide, why would the API still reject with 401? Any guidance would be greatly appreciated 🙏 @PowerBI REST API @ServicePrincipal @Authentication @admin Portal @AppRegistration
... View more