3

I'm trying to complete a fairly simple process:

  1. A web application, authenticated with Azure AD via a personal Microsoft account (i.e. an @hotmail account), makes a call to a second microservice.
  2. The microservice is secured via a JWT, obtains a second token using the on-behlaf-of flow, and called the Microsoft Graph API to retrieve calendar events.

I can log into the web frontend OK, and call the second microservice OK. The second microservice can obtain an on-behalf-of (obo) token OK, but the problem I run into is that the obo access token provided to me fails to call the Graph API. The error I receive is this:

{"error":{"code":"NoPermissionsInAccessToken","message":"The token contains no permissions, or permissions can not be
understood.","innerError":{"oAuthEventOperationId":"7499efa7-932b-425d-8ad4-43206630f961","oAuthEventcV":"ed1BzGz2t/H/wK7JnZB6lQ.1.1.1","errorUrl":"https://aka.ms/autherrors#error-InvalidGrant","requestId":"3ca5fa79-423b-460e-9130-b7d1172ec841","date":"2021-09-13T09:24:17"}}}

My problem is similar to the one described here, where my obo JWT does not contains a roles claim. This is the decoded JWT sent to the Graph API:

{
  "typ": "JWT",
  "nonce": "A3IzBCOGrnE53ukPqb2jHjWYT0grwFbHo_OkzcUhSRc",
  "alg": "RS256",
  "x5t": "l3sQ-50cCH4xBVZLHTGwnSR7680",
  "kid": "l3sQ-50cCH4xBVZLHTGwnSR7680"
}.{
  "aud": "https://graph.microsoft.com",
  "iss": "https://sts.windows.net/26375159-666a-4217-adfe-c06427b7798c/",
  "iat": 1631522998,
  "nbf": 1631522998,
  "exp": 1631526898,
  "acct": 1,
  "acr": "1",
  "aio": "AUQAu/8TAAAA1HEurZSE5YS0ADYs3oKeEEy6qhWwyXBZtoHtBPbIS/jo0OD5BTlQptuXZ3ZLtDczWZQw7b0+dUoCNdpN2mY4ew==",
  "altsecid": "1:live.com:00014B90C0D373BC",
  "amr": [
    "pwd"
  ],
  "app_displayname": "SpringBootMicroserviceDemo",
  "appid": "5907efc0-f0b5-45db-b4cf-725f655009c3",
  "appidacr": "1",
  "email": "matthewcasperson@hotmail.com",
  "family_name": "Casperson",
  "given_name": "Matthew",
  "idp": "live.com",
  "idtyp": "user",
  "ipaddr": "45.132.224.55",
  "name": "matthewcasperson",
  "oid": "e377a23b-1b88-4d14-9c99-fc6ecd4a41c7",
  "platf": "3",
  "puid": "1003200180F4FB20",
  "rh": "0.AVAAWVE3JmpmF0Kt_sBkJ7d5jMDvB1m18NtFtM9yX2VQCcNQAKM.",
  "scp": "Calendars.Read openid profile User.Read email",
  "signin_state": [
    "kmsi"
  ],
  "sub": "vhbBIoJqEHoEaJLMVsG5sh0C4FjoJiAfAKOFCzrC8hQ",
  "tenant_region_scope": "NA",
  "tid": "26375159-666a-4217-adfe-c06427b7798c",
  "unique_name": "live.com#matthewcasperson@hotmail.com",
  "uti": "ufe_nSFv_UuiYCOur72mAQ",
  "ver": "1.0",
  "wids": [
    "13bd1c72-6f4a-4dcf-985f-18d3b80f208a"
  ],
  "xms_st": {
    "sub": "PCUskXV6aCsNgHz9Yug42-WhS-iea1gy5GI5trkTZ4E"
  },
  "xms_tcdt": 1631479794
}.[Signature]

The JWT has Calendars.Read in the scp, but no roles, which appears to be an issue.

The JWT above will complete a call to the "me" endpoint OK (i.e. https://graph.microsoft.com/v1.0/me). Unfortunately, calling the "me" endpoint is as far as any example provided by Microsoft goes.

The sample application here provides a controller that shows calling the "me" endpoint on the Graph API, and if I modify the Graph API client to include the https://graph.microsoft.com/Calendars.Read scope, it also fails the Graph API request.

The sample application here appears to be a slightly older example in that it builds the token manually rather than injecting something like @RegisteredOAuth2AuthorizedClient("graph") OAuth2AuthorizedClient client (which is described in more detail on the Spring blog here). But again the sample only goes so far as to call the "me" endpoint.

As far as I'm aware I have enabled all the correct settings. My Azure AD Application has requested Calendars.Read both as a delegated and application permission, and the permissions have been granted consent:

enter image description here

My web based application can be found here, and the Calendar API microservice can be found here.

Further reading:

The crux of my issue is that using the on-behalf-of flow appears to be the recommended solution for calling the Graph API from a resource server that accepts a JWT from a front end application. Defining the delegated permissions in the Azure AD Application, consenting to them, defining them in an authorization-clients: in the application.yaml file, and getting a client via @RegisteredOAuth2AuthorizedClient("graph") OAuth2AuthorizedClient client are the only consistent instructions from the Microsoft documentation and sample applications. And yet the resulting JWT can only call the "me" endpoint.

Can anyone shed some light on how to call the Graph API with on-behalf-of token in Spring boot?

Phyxx
  • 15,730
  • 13
  • 73
  • 112

0 Answers0