azuremicrosoft-graph-apimicrosoft-graph-sdks

Authorisation error accessing user license information in Microsoft Graph Python


I'm using Microsoft Graph Python SDK to access user license information. Here is the code line:

license_details = await graph_client.users.by_user_id(user_id).license_details.get()

However, this keep throwing Authorization Error with following response:

APIError
  Code: 403
  message: None
  error: MainError(additional_data={}, code='Authorization_RequestDenied', details=None, inner_error=InnerError(additional_data={}, client_request_id='a0dc5684-d627-477b-af2c-1d264039e6de', date=DateTime(2024, 11, 13, 5, 59, 28, tzinfo=Timezone('UTC')), odata_type=None, request_id='f503re17-615b-46f4-afce-fc02bda244a2'), message='Insufficient privileges to complete the operation.', target=None)

My application has all necessary permissions like User.Read.All and Directory.Read.All with admin consent granted and correct credentials are used. Despite this, the error still occcurs.

The goal is to retrieve user’s license details, but instead, the 403 authorization error is being returned. Are there additional permissions required to access license details? Could there be an issue with Azure AD app configuration?

Thanks in advance for any help!


Solution

  • Note that, licenseDetails API endpoint does not support permissions of Application type. You can refer this MS Document.

    Initially, I too got same error when I tried to access user's license information with client credentials flow granting Application type permissions:

    enter image description here

    To resolve the error, switch to delegated flows like interactive or authorization code flow by granting LicenseAssignment.ReadWrite.All permission of Delegated type as below:

    enter image description here

    In my case, I used interactive flow for which redirect URI should be http://localhost in Mobile & Desktop applications platform with public client flow enabled:

    enter image description here

    When I ran below sample code and signed in with admin account, I got response with user's license information successfully as below:

    import asyncio
    from azure.identity import InteractiveBrowserCredential
    from msgraph import GraphServiceClient
    
    CLIENT_ID = 'appID'
    TENANT_ID = 'tenantID'
    SCOPES = ['LicenseAssignment.ReadWrite.All']
    
    credential = InteractiveBrowserCredential(
        client_id=CLIENT_ID,
        tenant_id=TENANT_ID
    )
    
    graph_client = GraphServiceClient(credential)
    
    async def get_user_license_details(user_id):
        try:
            license_details_response = await graph_client.users.by_user_id(user_id).license_details.get()
            license_details = license_details_response.value
    
            if license_details:
                print(f"License details for user {user_id}:")
                for license in license_details:
                    print(f"License SKU ID: {license.sku_id}")
                    print(f"SKU Part Number: {license.sku_part_number}")
    
                    if license.service_plans:
                        print("Assigned Service Plans:")
                        for plan in license.service_plans:
                            print(f"  Service Plan ID: {plan.service_plan_id}")
                            print(f"  Service Plan Name: {plan.service_plan_name}")
                            print(f"  Provisioning Status: {plan.provisioning_status}")
                            print(f"  Applies to: {plan.applies_to}")
                    else:
                        print("No assigned service plans found.")
            else:
                print(f"No license details found for user {user_id}.")
    
        except Exception as e:
            print(f"Error retrieving license details: {e}")
    
    async def main():
        user_id = 'userID'
        await get_user_license_details(user_id)
    
    asyncio.run(main())
    

    Response:

    enter image description here