Search code examples
azure-active-directorymicrosoft-graph-apioutlook-restapi

"One or more scopes are not compatible with each other" error when retrieving access token for the


I have an app that integrated with Outlook, Calendar via the Azure AD REST API v.2. I have tried to use the incremental and dynamic scopes to "upgrade" the user's token so that the app can access OneDrive as well, (so the user could directly upload her email attachments in her cloud). The authorization code retrieval redirects went well and the user is asked for the additional scope after login (files.readwrite). However, on step 2 when I try to obtain the access token I get the following error:

System.Exception: Acquire token by authorization code returned BadRequest: 

{
  "error": "invalid_scope",
  "error_description": "AADSTS70011: The provided value for the input parameter 'scope' is not valid. One or more scopes in 'https://outlook.office.com/mail.readwrite https://outlook.office.com/mail.send https://outlook.office.com/contacts.readwrite https://outlook.office.com/calendars.readwrite https://outlook.office.com/people.read files.readwrite' are not compatible with each other.\\r\\nTrace ID: b02fa0bf-6e86-4156-81e8-294dbc851500\\r\\nCorrelation ID: 3697bd18-554c-47e6-81cc-de3c47780fc9\\r\\nTimestamp: 2018-02-01 15:26:10Z",
  "error_codes": [
    70011
  ],
  "timestamp": "2018-02-01 15:26:10Z",
  "trace_id": "b02fa0bf-6e86-4156-81e8-294dbc851500",
  "correlation_id": "3697bd18-554c-47e6-81cc-de3c47780fc9"
}

Or this error:

System.Exception: Acquire token by authorization code returned BadRequest: 
{
  "error": "invalid_request",
  "error_description": "AADSTS700022: The provided value for the input parameter scope is not valid because it contains more than one resource. The scope https://outlook.office.com/mail.readwrite https://outlook.office.com/mail.send https://outlook.office.com/contacts.readwrite https://outlook.office.com/calendars.readwrite https://outlook.office.com/people.read files.readwrite is not valid.\\r\\nTrace ID: 9781d206-11b3-46c8-b972-8c4e77641c00\\r\\nCorrelation ID: 7e63af89-6e95-45f4-abaa-8f32051fb9ef\\r\\nTimestamp: 2018-02-01 15:36:32Z",
  "error_codes": [
    700022
  ],
  "timestamp": "2018-02-01 15:36:32Z",
  "trace_id": "9781d206-11b3-46c8-b972-8c4e77641c00",
  "correlation_id": "7e63af89-6e95-45f4-abaa-8f32051fb9ef"
}

I assume I can't use the same token for both Outlook and OneDrive access because they are "different resources", one being part of the Office 365 and the other in Microsoft graph, however, I struggle to find a comprehensive list of which resources are compatible with which in here (https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-scopes).

My question is, does this mean that I will need to maintain 2 different tokens (my app uses the offline scope to refresh the token) for OneDrive and Outlook?

Also is there a difference between OneDrive for a personal account and OneDrive for a business accounts (which I think is the same as Sharepoint)? When working with outlook I can use the same code for outlook.com and Office365 emails, but I am not sure this is the case when it comes to working with files.

With the Google APIs it's quite simple to just add the Google Drive (or any other API) scope to your Gmail access scopes, but I guess that's not the case with the Microsoft APIs.

Thanks


Solution

  • Yes you will need two tokens. As juunas said in his comment, the problem is the audience, or the aud parameter in the token. You're asking for scopes that apply to two different audiences: https://outlook.office.com and https://graph.microsoft.com.

    The good news is that these two APIs do have overlapping scopes, and Azure AD will allow you to use a refresh token issued for Graph to get a token for the Outlook API. So here's what I suggest (assuming you're doing authorization code flow)

    1. Do your authorization request using Graph scopes:

      mail.readwrite 
      mail.send 
      contacts.readwrite 
      calendars.readwrite 
      people.read 
      files.readwrite
      
    2. Do a token request with grant_type=authorization_code using those same Graph scopes. This gets your Graph token + refresh token.

    3. Do a token request with grant_type=refresh_token using the refresh token from previous step, but this time with ONLY the Outlook-applicable scopes, qualified for https://outlook.office.com. This gets your Outlook token.

      https://outlook.office.com/mail.readwrite 
      https://outlook.office.com/mail.send 
      https://outlook.office.com/contacts.readwrite 
      https://outlook.office.com/calendars.readwrite 
      https://outlook.office.com/people.read