Skip to content

MSAL Authentication via Service Principal (Python) to Power BI #374

@marossi10

Description

@marossi10

Describe the bug
I am trying to connect to a Power BI Workspace and Report. In order to do so, I need to get an access token. I'm following the steps of this article https://www.datalineo.com/post/power-bi-rest-api-with-python-and-microsoft-authentication-library-msal. However differently from this article I would like to authenticate via Service Principal. I don't understand why when I authenticate via User and Pwd I get the correct access token while when I authenticate via SP I get the error 'Get report failed 403'.

It follows the code for both types of authentication.

To Reproduce

--------------------------------------------------

Set Authentication variables for SP authentication

--------------------------------------------------

client_id = 'Service Principal Client ID'
client_secret = 'Service Principal Secret'
authority_url = 'https://login.microsoftonline.com/[my tenant]'
scope = ["https://analysis.windows.net/powerbi/api/.default"]
url_groups = 'https://api.powerbi.com/v1.0/myorg/groups'

--------------------------------------------------

Get the access token via SP authentication

--------------------------------------------------

app = msal.ConfidentialClientApplication(
client_id,
authority=authority_url,
client_credential=client_secret)

result = app.acquire_token_for_client(scopes=scope)

accessToken = result['access_token']

--------------------------------------------------

Set local variables for User and Pwd Authentication

--------------------------------------------------

client_id = 'Registered App Client ID'
username = 'my username'
password = 'my pwd'
authority_url = 'https://login.microsoftonline.com/[tenant]'
scope = ["https://analysis.windows.net/powerbi/api/.default"]
url_groups = 'https://api.powerbi.com/v1.0/myorg/groups'

--------------------------------------------------

Get the access token via User and Pwd Authentication

--------------------------------------------------

app = msal.PublicClientApplication(client_id, authority=authority_url)
result = app.acquire_token_by_username_password(username=username, password=password, scopes=scope)

-------------------------------------------------------------------------------------------------------------

Check if a token was obtained, grab it and call the Power BI REST API, otherwise throw up the error message

-------------------------------------------------------------------------------------------------------------

if 'access_token' in result:
access_token = result['access_token']
header = {'Content-Type':'application/json','Authorization': f'Bearer {access_token}'}
api_out = requests.get(url=url_groups, headers=header)
# print(api_out.json())
else:
print(result.get("error"))
print(result.get("error_description"))

accessToken = result['access_token']

print(accessToken)

--------------------------------------------------

Get the workspaces list

--------------------------------------------------

header = {'Content-Type': 'application/json', 'Authorization': f'Bearer {accessToken}'}
api_out_w = requests.get(url=url_groups, headers=header)
workspacesJson = api_out_w.json()

workspacesId = []
workspacesName = []
workspaces = {}

for w in workspacesJson['value']:
workspacesId.append(w['id'])
workspacesName.append(w['name'])

workspaces['id'] = workspacesId
workspaces['name'] = workspacesName

groupName = workspaces['name'][0] # forcing to choose the first workspace
groupId = workspaces['id'][0] # forcing to choose the first workspace

print('Got the workspace info, workspaceName:', groupName, ',workspaceId: ', groupId)

-------------------------------------------------

Get the reports list

--------------------------------------------------

header = {'Content-Type': 'application/json', 'Authorization': f'Bearer {accessToken}'}
api_out_r = requests.get(url=f'https://api.powerbi.com/v1.0/myorg/groups/{groupId}/reports', headers=header)
reportsJson = api_out_r.json()

reportsId = []
reportsName = []
reportsEmbedUrl = []
reports = {}

for r in reportsJson['value']:
reportsId.append(r['id'])
reportsName.append(r['name'])
reportsEmbedUrl.append(r['embedUrl'])

reports['id'] = reportsId
reports['name'] = reportsName
reports['embedUrl'] = reportsEmbedUrl

reportName = reports['name'][0]
reportEmbedUrl = reports['embedUrl'][0] # forcing to choose the first workspace

print('Got the report info, reportName:', reportName, ',reportEmbedUrl:', reportEmbedUrl)

Expected behavior
I would like to get the correct access token (as it happens when I authenticate via user and pwd).

What you see instead
'Get report failed 403'
image

**The MSAL Python version **
version 1.12.0

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions