Uncategorized

How to use Application Permission with Azure AD v2 endpoint

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.

Here we use Microsoft Graph, but you can also use other applications for this application permissions. See “Azure AD v2 endpoint – How to use custom scopes for admin consent” for other applications. (Added 02/07/2018)

When to use this permission ?

As l wrote in my early 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 interactive login UI, and can access to the all user objects, 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 (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 : For other applications except for “Microsoft Graph”, please see “Azure AD v2 endpoint – How to use custom scopes for admin consent“. (Added 02/07/2018)

Note : In the usual user consent’s flow, you don’t need to pre-define scopes in App Registration Portal and you can set scopes dynamically (on the fly) when you authenticate.
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();
}
Advertisements

Categories: Uncategorized

Tagged as:

37 replies »

  1. 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
    }}

    Like

    • 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)

      Like

  2. 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

    Like

  3. 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”}

    Like

    • 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.)

      Like

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

        Like

      • 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.

        Like

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

        Like

  4. Hi,

    After getting the access token I was trying to get the following resource (https://graph.microsoft.com/v1.0/me/message) which resulted in the following error:

    HTTP/1.1 400 Bad Request
    Cache-Control: private
    Transfer-Encoding: chunked
    Content-Type: application/json
    Server: Microsoft-IIS/8.5
    request-id: 95878061-9c50-4d67-934f-c50a4b98edc6
    client-request-id: 95878061-9c50-4d67-934f-c50a4b98edc6
    x-ms-ags-diagnostic: {“ServerInfo”:{“DataCenter”:”Japan East”,”Slice”:”SliceB”,”ScaleUnit”:”000″,”Host”:”AGSFE_IN_2″,”ADSiteName”:”KAW”}}
    Duration: 3.5795
    X-Powered-By: ASP.NET
    Date: Wed, 25 Jan 2017 06:01:48 GMT

    {
    “error”: {
    “code”: “BadRequest”,
    “message”: “Current authenticated context is not valid for this request”,
    “innerError”: {
    “request-id”: “95878061-9c50-4d67-934f-c50a4b98edc6”,
    “date”: “2017-01-25T06:01:49”
    }
    }
    }

    However if I change the resource uri to (https://graph.microsoft.com/v1.0/users/@.onmicrosoft.com/messages) I will be able to retrieve the mail messages.

    Why is this?

    Thanks in advance,
    Lei Xu

    Like

  5. Hi,

    Thanks to your post and answers I have managed to access office 365 resources with oauth2 client credentials flow through azure ad 2.0.

    I am looking for a little bit different two legged tutorial which use openid connect.

    I believe that openid connect for azure ad 2.0 login is in this format:

    https://login.microsoftonline.com/tenant/v2.0/.well-known/openid-configuration

    Wondering how to use this to achieve two legged authentication just like the oauth2 client credentials flow.

    Thanks in advance.

    Like

  6. Hi,

    thank you for your post.

    I followed the steps using crome rest client. I was able to give admin consent successfully. I also got the token created. But when i use that token to query graph apis, I am getting error
    “code”: “InvalidAuthenticationToken”,
    “message”: “CompactToken parsing failed with error code: -2147184105”,

    Please help me fix this issue

    Like

    • Are you using Microsoft Account to consent ? Even if it has the admin permissions, you cannot use Microsoft Account in this scenario. You need to use organization admin account (usually it has the format of *****@*****.onmicrosoft.com or provisioned custom domain) for consent.

      Like

  7. Hi,

    What is the correct way to specify both the “.default” and the “offline_access” scopes? When I try to add “offline_access” to the scope parameter while calling the token endpoint I get a incorrect scope error.

    Like

    • Hi, This (app permissions) is used for the backend (daemon app, backend services, etc) which uses certificates in the backend, so I think you cannot specify “offline” which is usually used for the mobile app that is preserving token as refresh token in the devices.

      Like

  8. H I am getting:
    Authorization_IdentityNotFound
    when I try to:
    var graphClient = new GraphServiceClient(“https://graph.microsoft.com/v1.0”, new DelegateAuthenticationProvider(
    async requestMessage => { string token =authResult.Token;
    requestMessage.Headers.Authorization = new AuthenticationHeaderValue(“bearer”, token);
    })
    var user = await this.graphClient.Users[emailAddress].Request().GetAsync()

    I have User.Read.All under both Delegated Permissions and Application Permissions

    Like

    • In your case, you don’t need application permissions, and also don’t need the delegated permissions previously set in App Reg Portal. (In v2 endpoint, you can set your required scopes on the fly like “https://login.microsoftonline.com/common/oauth2/v2.0/authorize?response_type=id_token+code&response_mode=form_post&client_id={your app id}&scope=openid+https%3a%2f%2fgraph.microsoft.com%2fmail.read&redirect_uri={your app url}&nonce=abcdef”.)

      I’m sorry but I’m not familiar with “Authorization_IdentityNotFound” error, and can you please give me the error status and messages on HTTP response by using Fiddler or something ?

      Like

  9. Please help! I keep getting error “The identity of the calling application could not be established”

    Like

    • Are you following the step by step procedure written in this post ? (Or you’re using SDK or some sort of things ?)
      If so, can you please give me the entire HTTP request and HTTP response of the error request ? (You can use Fiddler for tracking HTTPS if you’re using SDK.)
      I think this error seems to be the same as “Authorization_IdentityNotFound” which is mentioned in another comment.

      Like

  10. You’re guide has really helped me get my app working, but im currently running into an issue I can find a solution too and I think it might be related to an earlier comment. Im trying to get an outlook 365 calendar integration app to work and using your method for getting admin consent for an Azure AD tenant, I am successfully able to get an access token after the admin allows the app but I cannot get a refresh token. I have tried setting my requested permissions to have “allow_offline” and the allow offline permission shows up under the admin permission request screen but I still cant obtain a refresh token. Let me know what information you need. And thank you so much for this guide, its much more helpful than the microsoft documentation.

    Like

  11. Hi,

    I am using User-Administrator account to add permissions (User.Read.All) in my app. But when I re-login to the app it throws prompt with the following data : “NewApp needs permission to access resources in your organization that only an admin can grant. Please ask an admin to grant permission to this app before you can use it”.

    Please tell me the User-Administrator can access the all users data or not.

    Thank you.

    Like

    • Before using your app (named “NewApp”), the tenant administrator must add your app with admin consent. (This type of consent cannot be done by non-admin users.)
      After your app is consented by the tenant administrator, your app (“NewApp”) can access all users’ data in this tenant. For example, your app can sync all users’ information (in this tenant) with batch execution (like daemons).

      Like

  12. Hi,

    I’m trying to do a service-to-service call using Microsoft Graph API. The idea is my app will retrieve file data from a user’s personal OneDrive account (not OneDrive For Business) from time to time at the backend without doing user login. This user is a member in the Azure AD tenant.

    I followed steps above and able to retrieve access token. I can do API to retrieve list of users in the Azure AD tenant (i.e: https://graph.microsoft.com/v1.0/users) with the access token. But when I trying to access the user’s drive via API https://graph.microsoft.com/v1.0/users/{id}/drive, I get errors

    “code”: “BadRequest”
    “message”: “Tenant does not have a SPO license.”

    Did I missed out any permission setting on the application, or missing any licensing? Some said I need Office 365 to do this, but I doubt why? Or even, can I do this using application permission? (Microsoft documentation suggests to use delegated permission, but this does not fit my design.)

    I am new in this piece, sorry if I asked questions that are beyond this post. Any suggestion will be appreciated. Thanks in advanced.

    Like

    • Yes, you need each product’s license for calling corresponding APIs in Microsoft Graph. It seems that the error is saying that your tenant doesn’t have “SharePoint Online” license.
      (I also note that you cannot use this approach (with application permissions) for “personal OneDrive” account. It needs organization’s tenant.)

      Like

  13. Hello very cool site!! Guy .. Beautiful .. Amazing ..
    I’ll bookmark your web site and take the feeds additionally?
    I am happy to find a lot of useful info here in the
    put up, we’d like develop more strategies on this regard, thanks for sharing.

    . . . . .

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s