2
votes

Our application is managing Office 365 calendars without requiring explicit consent from users using the Office 365 Exchange Online API. This works as expected for existing installations at customers, but for new customer all requests to the Exchange Online API return a 401 Unauthorized response. We've narrowed this down to a roles claim missing in the JWT token.

Our question is if this roles claim missing in the JWT is a bug, or if this is by design. Perhaps someone from the Azure AD team can share their thoughts.

How to reproduce

In Azure AD, we've created an app registration. A public key has been uploaded in order to authenticate via ADAL4j. Next to this, some application permissions have been granted to Exchange Online:

application permissions

We can successfully request a access token via ADAL4j, using https://outlook.office365.com/ as the Resource Id. The JWT looks something like this (removed some irrelevant information):

{
    typ: "JWT",
    alg: "RS256",
},
{
    aud: "https://outlook.office365.com/",
    iss: "https://sts.windows.net/yyy/",
    app_displayname: "Test",
    appid: "app-id",
    ver: "1.0"
}

As can be seen, the property roles is missing in the JWT token.

When calling the Exchange Online API (e.g. https://outlook.office365.com/api/v2.0/users/[email protected]/calendars), sending the JWT as a Bearer token, a 401 Unauthorized is returned. The x-ms-diagnostics header mentions:

2000008;reason="The token contains no permissions, or permissions can not be understood.";error_category="invalid_grant"

Expected behaviour

When using an old application registration (created using the Azure Classic Portal, if I recall correctly), the JWT does contain a Roles property with the role we've requested:

{
    typ: "JWT",
    alg: "RS256",
},
{
    aud: "https://outlook.office365.com/",
    iss: "https://sts.windows.net/yyy/",
    app_displayname: "Test",
    appid: "app-id",
    roles: [
        "Calendars.ReadWrite.All"
    ],
    ver: "1.0"
}

Using this JWT as a Bearer token when calling the Exchange Online API works as expected.

Workaround

We've worked around the issue by using the Grant Permissions button for the new app registration:

grant permissions button

Now, the Calendars.ReadWrite.All role is present in the JWT, so everything is working as expected.

Question

In the past we've never had to execute the Grant Permissions action. Also, this page mentions (emphasis added):

As an administrator, you can also consent to an application's delegated permissions on behalf of all the users in your tenant. Administrative consent prevents the consent dialog from appearing for every user in the tenant, and can be done in the Azure portal by users with the administrator role. From the Settings page for your application, click Required Permissions and click on the Grant Permissions button

However, the "Read and write calendars in all mailboxes" permission is an application permission, and not a delegated permission, as mentioned at this page.

Is the workaround the correct solution to our missing Roles claim issue, or is something else wrong on the Azure AD side?

1
Some permissions don't require Admin cosent, But the other permssions need to require Admin consent. You can see if the permssions require admin consent in the portal. With AADv1 endpoint, grant permissions button can do the admin consent in advance. Also, Application permissions is for client_credentials flow and delegated permssions is for on-behalf-of users flow,like code grant flow. - Wayne Yang

1 Answers

3
votes

The workaround is the correct solution. When your application needs application permissions, an admin must consent by either clicking in the "grant permissions" button (as you did) or by passing admin_consent to the login URL. This applies to the AAD v1 application model. For the AAD v2 application model, there is a different way to get admin consent. More information here.

In the past (Azure Classic Portal), when you added application permissions to an application, the consent was granted automatically. This is not the case in the new Azure Portal.