Skip to content

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

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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