The difference between the tokens used by Microsoft Graph API and Azure AD Graph API
Microsoft Graph API and Azure AD Graph API are two sets of Restful services to query office 365 user or organization's information. The obvious difference for these two services are the endpoints that Microsoft Graph API is https://graph.microsoft.com and Azure AD Graph API is https://graph.windows.net.
On authorization part, both of the two Graph APIs are OAuth2.0 based. In authorization code flow (for web application), both of them are using https://login.microsoftonline.com/{tenant-id}/oauth2/authorize to require authorization code, using https://login.microsoftonline.com/{tenant-id}/oauth2/token to require token. Any other difference? Looks like we just need take care of the API endpoint, all the other parts are exactly the same?
If you have one application works well to call Microsoft Graph while always get 401 Unauthorized error (Access Token missing or malformed) in Azure AD Graph and vice versa, the following regarding to the token difference probably solve the problem.
Let's begin with Office 365 APIs for Calendar Sample which is a good material in github to learn Microsoft Graph. You can follow the lab to make sure it works, then capture fiddler log and summarize the parameter exchange shown below.
Flow to call Microsoft Graph API
- Require authorization code with the following parameter
client_id <client id assigned to the app>
response_mode form_post
response_type code id_token
scope openid profile
- Require token with the following parameter
resource https://graph.microsoft.com/
client_id <client id assigned to the app>
client_secret <client secret assigned to the app>
- Call API successfully, for example https://graph.microsoft.com/v1.0/{tenant-id}/Me/events
Now, let's just keep the first two steps exactly the same, and only change the third step's code to call Azure AD Graph API such as https://graph.windows.net/{tenant-id}/contacts?api-version=1.6. you will receive"Access Token missing or malformed" error shown below. We have not changed the token manually also it is generated by Microsoft STS, how could it be malformed?
Copy the token to jwt.io, we can see the token itself is valid shown below:
{
"aud": "https://graph.microsoft.com/",
"iss": "https://sts.windows.net/ad62fe15-581b-4d16-98bf-6195c99d5f06/",
"iat": 1473758051,
"nbf": 1473758051,
"exp": 1473761951,
"acr": "1",
"amr": [
"pwd"
],
While, something interesting is the aud part is https://graph.microsoft.com which is the endpoint for Microsoft Graph, is it applicable for Azure AD graph? Based on JWT RFC, we understand "The "aud" (audience) claim identifies the recipients that the JWT is intended for. Each principal intended to process the JWT MUST identify itself with a value in the audience claim. If the principal processing the claim does not identify itself with a value in the "aud" claim when this claim is present, then the JWT MUST be rejected. " That means the audience identify who will consume the token. Apparently, Microsoft Graph's audience should be https://graph.microsoft.com and Azure AD Graph's audience should be https://graph.windows.net. Similarly, if you have developed your own Restful service based on Microsoft OAuth, and also another web application to call this Restful service, the audience need be changed accordingly.
Now, let's change the code and make sure https://graph.windows.net is passed as resource to both of AcquireTokenByAuthorizationCode and AcquireTokenSilentAsync, the sample will work for Azure AD Graph now. We have used .Net MVC authorization code flow as example here, the logic applies to any other programming languages and authorization flow as well.
Comments
- Anonymous
September 13, 2016
Hi Wu Shuai, Thanks for sharing these insights. Really helpful. - Anonymous
December 10, 2016
Thanks Wu Shuai!This solved my problem wondering why a AAD token worked but not MS Graph API..MS should group them within a single unified API, else it's really confusing.