Search code examples
pythonazureazure-active-directorymicrosoft-graph-apioffice365

How to authenticate on msgraph.GraphServiceClient?


There is no documentation for do this, I found it unacceptable.

from msal import ConfidentialClientApplication
from msgraph import GraphServiceClient

client_id = ''
client_secret = ''
tenant_id = ''
authority = f'https://login.microsoftonline.com/{tenant_id}'
scopes = ['https://graph.microsoft.com/.default']

app = ConfidentialClientApplication(
    client_id,
    authority=authority,
    client_credential=client_secret,
)

response = app.acquire_token_for_client(scopes)

graph_client = GraphServiceClient(
    credentials=response,
    scopes=scopes
)


await graph_client.users.get()
/usr/local/lib/python3.10/dist-packages/kiota_authentication_azure/azure_identity_access_token_provider.py in get_authorization_token(self, uri, additional_authentication_context)
    101                 )
    102             else:
--> 103                 result = self._credentials.get_token(*self._scopes, claims=decoded_claim)
    104 
    105             if inspect.isawaitable(result):
> AttributeError: 'dict' object has no attribute 'get_token'

Analyzing the stack, you can see that the object passed as credentials in the `msgraph` client is not what it expects; `acquire_token_for_client` returns a dictionary, but `GraphServiceClient` expects it to have a function called "get_token."

How can this be resolved?


Solution

  • I registered one Entra ID application and granted User.Read.All permission of Application type as below:

    enter image description here

    Initially, I too got same error when I ran your code to fetch list of users like this:

    from msal import ConfidentialClientApplication
    from msgraph import GraphServiceClient
    
    client_id = ''
    client_secret = ''
    tenant_id = ''
    authority = f'https://login.microsoftonline.com/{tenant_id}'
    scopes = ['https://graph.microsoft.com/.default']
    
    app = ConfidentialClientApplication(
        client_id,
        authority=authority,
        client_credential=client_secret,
    )
    
    response = app.acquire_token_for_client(scopes)
    
    graph_client = GraphServiceClient(
        credentials=response,
        scopes=scopes
    )
    
    
    result = await graph_client.users.get()
    print(result)
    

    Response:

    enter image description here

    To resolve the error, make use of below modified code that uses client credentials flow to authenticate with MS Graph and listed users successfully:

    import asyncio
    from azure.identity import ClientSecretCredential
    from msgraph import GraphServiceClient
    
    tenant_id = "tenantID"
    client_id = "appID"
    client_secret = "secret"
    
    credential = ClientSecretCredential(
        tenant_id=tenant_id,
        client_id=client_id,
        client_secret=client_secret
    )
    
    client = GraphServiceClient(credential)
    
    async def main():
        result = await client.users.get()
        users = result.value
    
        for user in users:
            print("User ID:", user.id)
            print("User Display Name:", user.display_name)
            print("-" * 50)  # Separating each user with a line
    
    asyncio.run(main())
    

    Response:

    enter image description here

    References:

    List users - Microsoft Graph

    GitHub - microsoftgraph/msgraph-sdk-python