I've blogged twice (here and here) about authentication using the msal Python module. I'm going to cap off this topic with a third and final entry by moving onto the azure-identity module.
When I first looked at Azure authentication for the Power BI REST API, I honestly kind of fell into using the msal library first. I found it easy to use and went on to blog about it. Recently, I needed to use the azure-identity module took the time to try it out for getting access tokens to call the Power BI APIs.
msal versus azure-identity - which to use?
You might ask what the difference is between the two. In simple terms, the azure-identity is part of the Azure SDK and actually uses the msal module under the bonnet (or hood, depending where you're from). They have a lot of overlap but what I have found is that if your purpose is to call the Power BI APIs, there's little difference.
For other purposes like building an app or integrating into your own solution, then you may want to dig a little deeper on which is the right one to use. I found this discussion (here) on GitHub which some Microsoft people kindly responded to in order to clarify it better than I am doing.
Sample scripts
To align to the sample scripts I had in the first blog, I have below three ways you can obtain a token to pass to the Power BI Rest API.
You may spot that I'm not passing an authority URL, as it happens it defaults to login.microsoftonline.com so works fine in these cases.
from azure.identity import ClientSecretCredential, InteractiveBrowserCredential, UsernamePasswordCredential
tenant_id = '1234abcd-1234-56787-ab12-abcdefg123456'
client_id = '1234abcd-1234-56787-ab12-abcdefg123456'
client_secret = 'abcdefg123456***abcdefg123456'
scope = 'https://analysis.windows.net/powerbi/api/.default'
username = 'youraccount@domain.com'
password = 'YourMegaSafePassword738!*'
# ---------------------------------------
# Option 1 for getting the token. If you don't want any credentials saved or the user has multi-factor configured on their account, the user can interactively authenticate
# ---------------------------------------
interactive_browser_credential_class = InteractiveBrowserCredential()
access_token_class = interactive_browser_credential_class.get_token(scope)
token_string = access_token_class.token
# ---------------------------------------
# Option 2 for getting the token. You can save the username and password and get a token without interacting
# IMPORTANT: this won't work if the username has Multi-Factor Authentication enabled
# ---------------------------------------
username_password_credential_class = UsernamePasswordCredential(client_id=client_id, username=username, password=password, tenant_id=tenant_id)
access_token_class = username_password_credential_class.get_token(scope)
token_string = access_token_class.token
# ---------------------------------------
# Option 3 for getting the token. If authenticating via client/client_secret
# ---------------------------------------
client_secret_credential_class = ClientSecretCredential(tenant_id=tenant_id, client_id=client_id, client_secret=client_secret)
access_token_class = client_secret_credential_class.get_token(scope)
token_string = access_token_class.token
I also note, that if you are using azure-identity to authenticate to services like Azure Storage, you can simply pass the credential class (for e.g. defined as interactive_browser_credential_class in the sample script) as a parameter, without the need to extract a token string. This is like passing the Credential object in PowerShell.
My decision
I think I'll use azure-identity from now on. It's a little bit simpler!
Relevant Links
Azure Identity Credential Classes
Discussion on GitHub about the two options
Blog Part I
Blog Part II