How to use Application Permission with v2 endpoint and Microsoft Graph


The following scenario of OAuth flow is sometimes needed for the real applications, but this scenario is not supported in the first release of Azure AD v2.0 endpoint. (For v1 endpoint, it’s supported.)

In this blog post, I introduce the recently supported new flow using application permissions with v2.0 endpoint, and explain how it works and how to use with new v2.0 endpoint and Microsoft Graph.

When to use this permission ?

As l wrote in the previous post “How to build backend server-side app (Deamon, etc) using Azure AD v1 endpoint” (sorry, which is written in Japanese), the client credential authentication using application permissions is very strong and powerful OAuth flow for applications.

Imagine that you want to synchronize the organization users in your app with Azure AD users periodically. This sync app would work with no login UI (as daemon or services) and access to the all Azure AD users (read/write).
Using the usual OAuth flow (code grant flow, etc), this is impossible.

The following flow uses the organization-level access privilege using the certificate or password (app secret) without login UI, and can access to the all users, all messages, all calendars, all files, all contacts, all registered devices, etc in the granted organization.
This flow exactly helps the previous scenarios.

Note : The usual user authentication using v2.0 endpoint and Microsoft Graph (which is the commonly used OAuth 2.0 code grant flow) is described in the previous post “OAuth flow by v2.0 endpoint using unified Microsoft identity (Azure AD Account and Microsoft Account)“. (Sorry, it’s also written in Japanese…)

Application Registration

Before using this flow, you must register your application.

You login to https://apps.dev.microsoft.com (the app registration portal), and please add your app pushing “add your app” button.
After the application is created, you can get the application id in the application page. (see the following screenshot)

In “Microsoft Graph Permissions” section on the application page, you can see the following “Application Permissions” area.
In this area, please push “add” button and select “Files.Read.All”.

Note : In the usual v2.0 endpoint flow, you can use the scope (permission) values on the fly. (You don’t need to pre-define this permission values.) But, as I explain later, this flow uses the pre-defined scope attached on your application.

In “Application Secrets” section, you can create the application password (application secret) or asymmetric certificate (key pair). This time, press “Generate New Password” button and create the application secret (password).

Lastly, in “Platforms” section, please press “Add Platform”, add the Web platform, and set your application’s url as redirect uri. (See the following screenshot)
In this example, we use “https://localhost/testapp02” as redirect uri.

Save all settings.

Admin Consent

We assume that this application (service) is multitenant application and share this service for user’s organization. How to deliver this application for each organization (tenant) ?

In this case, you can use the delivery mechanism called “consent”.
For example, if you use the Facebook integrated application, the application informs you operations (“read your friend list”, “create posts”, etc) the application is needing. If the user approve, the user can use this application. No extra setup is needed.
The application using Microsoft identity is having the same mechanism, and this is called “user consent” which grants the application to access your own data (your messages, your files, etc).

But as I wrote above, this application uses the all organization’s data, not for the specific user. In such a case, the “administrator consent” (admin consent) is used in Azure AD, and this consent must be done by the administrator in the organization.

Note : The admin consent is not only for the application permission, but also used to grant delegated permissions (user permissions) to all users in your organization.

When you use the administrator consent, all you have to do is to go to https://login.microsoftonline.com/{tenant name}/adminconsent?client_id={application id}&state={some state data}&redirect_uri={redirect uri} using web browser.
In this example, we go to the following url. (We assume the user tenant is testdirectory.onmicrosoft.com.)

https://login.microsoftonline.com/testdirectory.onmicrosoft.com/adminconsent?client_id=6abf3364-0a60-4603-8276-e9abb0d843d6&state=12345&redirect_uri=https%3a%2f%2flocalhost%2ftestapp02

Note : The state parameter is returned as the same value after login. Your application can use this data (state), if you want to keep some state after login.

If you access to the above url, the login screen (the following screenshot) is shown. Before using this application, the tenant administrator must login and permit to use this application only once, and the login is needed no longer.
When you are using v2.0 endpoint, you can use both Azure AD Account (organizational account) and Microsoft Account (personal account). But, in this case, this application needs the organization-level permission, then you must login using Azure AD tenant administrator’s account here. (If you use the other kind of account, the error occurs.)

After you login using the administrator account of Azure AD, the following consent screen is displayed. This screen says that if you grant to this application, this app takes the organization-level access privilege.

If you agree this consent, this application is granted to access your organization’s data. After that, the web page is redirected to {redirect uri}?admin_consent=True&tenant={tenant name}&state={state data}. In this example, this is the following url.

https://localhost/testapp02?admin_consent=True&tenant=testdirectory.onmicrosoft.com&state=12345

Note : If the error occurs, the page is redirected to the following uri.
http://localhost/testapp02?error=permission_denied&error_description=The+admin+canceled+the+request

If you don’t need this application anymore, you can revoke this application in Azure Portal. (Soon the new Azure Portal (Ibiza) will support this feature.)

Note : If you change your application permission in this application, the users (tenant administrators) must consent to this application again. (The user can consent many times.)

Get Access Token

Now it’s ready ! Your application can get the access token including permissions (scope or roles) and call some proper operations by the given permissions.

Your application can get access token using the following HTTP request (OAuth).
Note that you cannot use https://login.microsoftonline.com/common/oauth2/v2.0/token (which is commonly used) for getting the token. Instead, you must use https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token, which identifies the specific tenant. (In this example, we use “testdirectory.onmicrosoft.com” as user’s organization.)

The scope must be “https://graph.microsoft.com/.default”.
In the usual v2.0 endpoint authentication flow, you can use the scope (permission) values on the fly like https://graph.microsoft.com/mail.read. But, this scope (.default) means that the application uses the pre-defined scope (which is “Files.Read.All” in this example).

POST https://login.microsoftonline.com/testdirectory.onmicrosoft.com/oauth2/v2.0/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&client_id=6abf3364-0a60-4603-8276-e9abb0d843d6&client_secret=JfgrNM9CcW...&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default

Your application can get the following HTTP response. The access token is used for calling APIs (services).

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "token_type": "Bearer",
  "expires_in": 3599,
  "ext_expires_in": 0,
  "access_token": "eyJ0eXAiOi..."
}

Call Services (Microsoft Graph)

Lastly your application calls the service of Microsoft Graph using the provided access token.
In this example, the “Files.Read.All” permission is used for your application, then your application can read the all user’s files using Microsoft Graph in the given organization (testdirectory.onmicrosoft.com).
The following is retrieving all files in the OneDrive root folder for the user “demouser01@testdirectory.onmicrosoft.com”. The result is returning the two folder items.
Your application can get the files of arbitary users in the organization in the same way.

HTTP Request

GET https://graph.microsoft.com/v1.0/users/demouser01@testdirectory.onmicrosoft.com/drive/root/children
Accept: application/json
Authorization: Bearer eyJ0eXAiOi...

HTTP Response

HTTP/1.1 200 OK
Content-Type: application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8

{
  "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('demouser01%40testdirectory.onmicrosoft.com')/drive/root/children",
  "value": [
    {
      "createdBy": {
        "user": {
          "id": "cf258756-2623-47cb-be46-c85d436265bb",
          "displayName": "Demo Taro"
        }
      },
      "createdDateTime": "2015-12-22T07:24:46Z",
      "eTag": "\"{4C06E4DE-B89C-4A78-848A-FCC6118041F6},1\"",
      "id": "01B6UXIPO64QDEZHFYPBFIJCX4YYIYAQPW",
      "lastModifiedBy": {
        "user": {
          "id": "cf258756-2623-47cb-be46-c85d436265bb",
          "displayName": "Demo Taro"
        }
      },
      "lastModifiedDateTime": "2016-05-23T11:45:24Z",
      "name": "testfol",
      "webUrl": "https://o365directory-my.sharepoint.com/personal/demouser01_o365directory_onmicrosoft_com/Documents/testfol",
      "cTag": "\"c:{4C06E4DE-B89C-4A78-848A-FCC6118041F6},0\"",
      "folder": {
        "childCount": 2
      },
      "parentReference": {
        "driveId": "b!iXgvhy0l90q10oljtqrTKLCkDzZ204FFhgSqDnNXhktfZNOb9jHxQrzimH24Z67t",
        "id": "01B6UXIPN6Y2GOVW7725BZO354PWSELRRZ",
        "path": "/drive/root:"
      },
      "size": 0
    },
    {
      "createdBy": {
        "user": {
          "id": "cf258756-2623-47cb-be46-c85d436265bb",
          "displayName": "Demo Taro"
        }
      },
      "createdDateTime": "2016-05-20T12:57:32Z",
      "eTag": "\"{2135DDF2-5458-49E6-8C8E-2AB08501A7E4},1\"",
      "id": "01B6UXIPPS3U2SCWCU4ZEYZDRKWCCQDJ7E",
      "lastModifiedBy": {
        "user": {
          "id": "cf258756-2623-47cb-be46-c85d436265bb",
          "displayName": "Demo Taro"
        }
      },
      "lastModifiedDateTime": "2016-05-20T13:04:11Z",
      "name": "expense",
      "webUrl": "https://o365directory-my.sharepoint.com/personal/demouser01_o365directory_onmicrosoft_com/Documents/expense",
      "cTag": "\"c:{2135DDF2-5458-49E6-8C8E-2AB08501A7E4},0\"",
      "folder": {
        "childCount": 2
      },
      "parentReference": {
        "driveId": "b!iXgvhy0l90q10oljtqrTKLCkDzZ204FFhgSqDnNXhktfZNOb9jHxQrzimH24Z67t",
        "id": "01B6UXIPN6Y2GOVW7725BZO354PWSELRRZ",
        "path": "/drive/root:"
      },
      "size": 0
    }
  ]
}

Using Microsoft Authentication Library (MSAL)

Microsoft Authentication Library (MSAL) is the library that helps you to develop applications that work with v2.0 endpoint. Now this also supports this scenarios.

The following is the C# MSAL sample code, which gets the access token for this application permission’s scenario.
You must install the NuGet package “Microsoft.Identity.Client” (Microsoft Authentication Library, MSAL) in your project.

using Microsoft.Identity.Client;

static void Main(string[] args)
{
  // get access token including application permissions
  ConfidentialClientApplication cl = new ConfidentialClientApplication(
    "https://login.microsoftonline.com/testdirectory.onmicrosoft.com/v2.0",
    "6abf3364-0a60-4603-8276-e9abb0d843d6",
    "https://localhost/testapp02",
    new ClientCredential("JfgrNM9CcW..."),
    new TokenCache());
  AuthenticationResult authResult = cl.AcquireTokenForClient(
    new string[] { "https://graph.microsoft.com/.default" },
    null).Result;

  Console.WriteLine(authResult.Token);
  Console.ReadLine();
}
Comments (15)

  1. SS says:

    Hi , I am getting
    {StatusCode: 403, ReasonPhrase: ‘Forbidden’, Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
    {
    Transfer-Encoding: chunked
    request-id: 83d0d501-2290-44cc-aa84-cb49975a4404
    client-request-id: 83d0d501-2290-44cc-aa84-cb49975a4404
    x-ms-ags-diagnostic: {“ServerInfo”:{“DataCenter”:”East US”,”Slice”:”SliceA”,”ScaleUnit”:”003″,”Host”:”SDFS”,”ADSiteName”:”CST”}}
    Duration: 61.6349
    Cache-Control: private
    Date: Thu, 13 Oct 2016 22:38:57 GMT
    Server: Microsoft-IIS/8.5
    X-Powered-By: ASP.NET
    Content-Type: application/json
    }}

  2. SS says:

    I have me sure that all the permission are given correctly

    1. Hi, If you have already consented (agreed with the permission request UI), please revoke this permission and approve again (by admin user).
      If you still cannot solve this, could you please attach your HTTP request raw ? (including authorization token)

  3. The app works on selecting entry and exit point is programmed

  4. Application content fingers heads do I

  5. Applications do not relieve programs road intersection and earn a pattern you carry responsibility for the delay of the signature.

  6. dejan says:

    Hi
    I’m using MSAL PublicClientApplication to connect to outlook.com.

    Works great, very easy to use, but in “confirming permissions” screen, in addition to “read contacts” permission I defined in “scopes” ({https://outlook.office.com/contacts.read”}) and in the app registration, there are four others permissions including “[APP] will be able to see and update your info, even when you’re not using this app.”. Am I missing something here? How can I remove these?
    Regards
    Dejan

    1. Are you using delegated permissions on the fly ? (i.e, are you setting “https://outlook.office.com/contacts.read” as “scope” value for the login ?)
      In this case, you don’t need to select any permissions in the app registration portal.
      I’m sorry it’s written by Japanese, but I’m writing this usual case (using the delegated permissions on the fly) in the following post.
      https://blogs.msdn.microsoft.com/tsmatsuz/2016/03/08/azure-ad-msa-v2-endpoint-validate-id_token/
      In this post, the following url is used for user’s login (the confirming permission’s screen is displayed), and you don’t need to select any permissions in the app registration portal beforehand.

      https://login.microsoftonline.com/common/oauth2/v2.0/authorize?response_type=id_token+code&response_mode=form_post&client_id=7822587c-fed4-4dd3-8e68-165334eb7c92&scope=openid+https%3a%2f%2fgraph.microsoft.com%2fmail.read&redirect_uri=https%3A%2F%2Flocalhost%2Ftest.php&nonce=abcdef

      1. dejann says:

        Hi,
        Thanks for your reply.
        Not sure if I explained well. I’m using MSAL public client from a UWP application. In the user authentication screen there are 4 additional permissions user has to agree with (in addition to the permission I defined in scope). So this is in the user authentication screen, not in the application configuration portal. One of these permissions sound scary, telling user that the app can change their data even when they are not using the app! I’m sure many users will be put off by this and may think the app is some sort of malware. Is there any way to change this?

        1. Can you please tell the following 2 questions ?
          1 ) Did you clear all “Microsoft Graph Permissions” in the app settings in app reg portal (https://apps.dev.microsoft.com) ?
          2 ) What kind of scopes did you set in MSAL code ?

  7. dejan says:

    1) Originally I had MS Graph delegated permissions in the app portal match what’s in my application code (scopes). I have now removed it. No change.
    2) In the app, scopes are defined as: {“https://outlook.office.com/contacts.readwrite”}

    1. Thank you for your reply again. I checked using my sample app, and I also found “access your data any time” when I’ve add “offline_access” in the scopes. (If I erase this offline_access, this permission message has disappeared.)
      If you set offline_access, not only access token but the refresh token is also returned. Using this refresh token, the app can always get access token inside the app, and can proceed some granted operations. This means “access your data any time”.
      For example, if the app is mobile app, this refresh token enables some operations without logging in again. Most mobile apps with OAuth 2 are using this refresh token, because the users must input their user name and password again and again. But, if your app is web app, you may erase this offline_access and prompt to the user to login again when the access token is expired. (The access token lifetime is 1 hour by default.)

      1. dejan says:

        Hi,
        Thanks for that! How do I erase offline_access permission? I don’t have that in scopes.

        1. Are you using some sort of library like MSAL ? If so, the libarary would add the “offline_access” automatically because of enabling cache.
          As you know, you can see the http raw using Fiddler and you can check what kind of scopes is added for the http request. If the issue exists, could you please tell me your http raw request ? I will try the same request.

          1. dejan says:

            Yes, using MSAL. I guess there is no way to switch it off with msal. Thanks for all the help!

Skip to main content