简体   繁体   中英

Azure AD: “scope” Property Missing from Access Token Response Body

I am writing a Python script to edit an Excel spreadsheet that lives in SharePoint. We have Office 365 for Business. I am using Microsoft Graph API. I registered the Python app with Microsoft Azure Active Directory (AD) and added the following 2 (app-only) permissions for Graph API: (1) Read and write files in all site collections (preview) and (2) Read directory data. (I had our company administrator register the app for me.)

My Python script uses the requests library to send REST requests:

import json
import requests

MSGRAPH_URI = 'https://graph.microsoft.com'
VERSION = 'v1.0'

def requestAccessToken(tenant_id, app_id, app_key):
    MSLOGIN_URI = 'https://login.microsoftonline.com'
    ACCESS_TOKEN_PATH = 'oauth2/token'
    GRANT_TYPE = 'client_credentials'
    endpoint = '{0}/{1}/{2}'.format(MSLOGIN_URI, tenant_id, ACCESS_TOKEN_PATH)
    headers = {'Content-Type': 'Application/Json'}
    data = {
        'grant_type': GRANT_TYPE,
        'client_id': app_id,
        'client_secret': app_key,
        'resource': MSGRAPH_URI

    }
    access_token = response.json()['access_token']
    return access_token

def getWorkbookID(access_token, fileName):
    endpoint = '{0}/{1}/me/drive/root/children'.format(MSGRAPH_URI, VERSION)
    headers = {
        'Content-Type': 'Application/Json',
        'Authorization': 'Bearer {}'.format(access_token)
    }
    response = requests.get(endpoint, headers=headers)
    print response.text
    assert response.status_code == 200
    items = response.json()['value']
    workbook_id = None
    for item in items:
        if item['name'] == fileName:
            workbook_id = item['id']
    return workbook_id

access_token = requestAccessToken(TENANT_ID, APP_ID, APP_KEY)
workbook_id = getWorkbookID(access_token, WORKBOOK_FILENAME)

The Python app successfully requests and receives an access_token from the Microsoft server. The access token starts like this

eyJ0eXAiOiJKV1QiLCJub25jZSI6...

Then it requests a list of my files in getWorkbookID():

GET https://graph.microsoft.com/v1.0/me/drive/root/children
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJub25jZSI6...

This is the response to that REST request:

{
  "error": {
    "code": "InternalServerError",
    "message": "Object reference not set to an instance of an object.",
    "innerError": {
      "request-id": "aa97a822-7ac5-4986-8ac0-9852146e149a",
      "date": "2016-12-26T22:13:54"
    }
  }
}

Note that I successfully get a list of my files when I request it via Graph Explorer ( https://graph.microsoft.io/en-us/graph-explorer ).

EDIT:

  1. Changed the title from "Microsoft Graph API Returns Object reference not set to an instance of an object" to "Azure AD "scope" Missing from Access Token Response".
  2. Changed the "me" in the uri of the GET request to "myOrganization", after reading this: graph.microsft.io/en-us/docs/overview/call_api

That is,

GET https://graph.microsoft.com/v1.0/myOrganization/drive/root/children
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJub25jZSI6...

Now get the following response.

{
  "error": {
    "code": "AccessDenied",
    "message": "Either scp or roles claim need to be present in the token.",
    "innerError": {
      "request-id": "bddb8c51-535f-456b-b43e-5cfdf32bd8a5",
      "date": "2016-12-28T22:39:25"
    }
  }
}

Looking at an example in graph.microsoft.io/en-us/docs/authorization/app_authorization, I see that the access token response body contains a "scope" property that lists the permissions granted for the app during the app's registration. However, the access token response I receive from the server does not have the "scope" property. Here is what my access token response looks like.

{
"token_type":"Bearer",
"expires_in":"3599",
"ext_expires_in":"0",
"expires_on":"1482968367",
"not_before":"1482964467",
"resource":"https://graph.microsoft.com",
"access_token":"eyJ0eXAiOiJKV..."
}

Questions:

  1. I had the administrator register the app in Azure AD and check the boxes for the Microsoft Graph API application permissions needed. Apparently that is not enough. What else is needed? Why are the permissions not in the access token response body?
  2. What is the correct URI for the GET request? Is "MyOrganization" the correct value in the URI?

Thanks all for your responses. After more research, I found the answer to my question.

The original problem: "Microsoft Graph API Returns Object reference not set to an instance of an object"

The request

GET https://graph.microsoft.com/v1.0/me/drive/root/children
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJub25jZSI6...

gets the response

{
  "error": {
    "code": "InternalServerError",
    "message": "Object reference not set to an instance of an object.",
    "innerError": {
      "request-id": "aa97a822-7ac5-4986-8ac0-9852146e149a",
      "date": "2016-12-26T22:13:54"
    }
  }
}

As @SriramDhanasekaran-MSFT noted, /me refers to the currently signed-in user. In our case, we do not have a signed-in user, so we cannot use /me . Instead, we can either use /myOrganization or nothing, it is optional.

The updated problem: "Azure AD "scope" Property Missing from Access Token Response"

The updated (replaces /me with /myOrganization) request

GET https://graph.microsoft.com/v1.0/myOrganization/drive/root/children
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJub25jZSI6...

gets the response

{
  "error": {
    "code": "AccessDenied",
    "message": "Either scp or roles claim need to be present in the token.",
    "innerError": {
      "request-id": "bddb8c51-535f-456b-b43e-5cfdf32bd8a5",
      "date": "2016-12-28T22:39:25"
    }
  }
}

As @SriramDhanasekaran-MSFT and @DanKershaw-MSFT mentioned, the reason why the access_token response was missing the scope property is that the permissions had not been "granted" in Azure AD by the administrator.

However, the solution that @SriramDhanasekaran-MSFT provided:

https://login.microsoftonline.com/common/oauth2/authorize?client_id=&response_type=code&redirect_uri=http://localhost&resource=https://graph.microsoft.com&prompt=consent

doesn't help me because my app doesn't have a redirect uri . The solution to granting the permissions is simpler than that: simply have the administrator login in to Azure AD and click the "Grant Permissions" link to grant the permissions.

Additionally, /myOrganization/driver/root/children lists the contents of the administrator's drive. As @PeterPan-MSFT noted, to list a different user's drive, replace /myOrganization with /users/<user-id> .

Success:

My application can now edit my Excel spreadsheets online, without the intervention of a human user. Contrary to what @PeterPan-MSFT stated, this is possible with Graph API and there is no need to download the Excel spreadsheet and edit offline.

Summary:

There were two problems: (1) using /me and (2) the application permissions had not been granted in Azure AD by the administrator.

Since client_credential token flow is being used (ie, there is no authenticated user context), any request with /me is not valid as /me refers to current signed-in user. Please try with delegated token if you to access files in user's drive.

To access root drive in Sharepoint, request url is /drive/root/children (myorganization is optional).

With regards to missing claims, admin has to consent the app. You can force consent by asking the admin to access the below url (replace with that of your app's)

https://login.microsoftonline.com/common/oauth2/authorize?client_id= &response_type=code&redirect_uri= http://localhost&resource=https://graph.microsoft.com&prompt=consent

As @juunas said, the first error information below should be the NULL exception in .NET which be caused at the server end, but also not an API bug or a permission issue.

 error": { "code": "InternalServerError", "message": "Object reference not set to an instance of an object.", 

You can refer to the SO thread to know this case which seems to update for backend, please try again later.

To explain for the second error when you changed the option me to myOrganization in the Graph API url, as @SriramDhanasekaran-MSFT, it's accessing files for the current user or a specified user with <user-id> instead of me .

However, based on my understanding, you want to edit an Excel spreadsheet lived in SharePoint for your orgnization, it seems to be not suitable via using Graph APIs. Per my experience, it should be done via using the APIs of OneDrive for Business to copy the Excel file to local to edit & upload to overwrite it, please refer to the dev documents for OneDrive and try to use the API for drive resource .

Hope it helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM