App Service Auth and the Azure AD Graph API

This post demonstrates how an App Service Web, Mobile, or API app can be configured to call the Azure Active Directory Graph API on behalf of the logged-in user. If you haven’t read it already, this post extends from my previous one on the Azure App Service Token Store.

Configuration

The default setup for Azure AD that we use does not include the configuration required for your app to call into the Graph API. However, there are a couple one-time configuration changes that you can make to enable this. In the future, we plan to make this as simple as clicking a button or checkbox in the portal, but until that happens, there is some additional setup required.

Step 1: Update Azure AD Configuration in Azure AD Portal

You can find and manage your Azure AD application in the legacy Azure Portal at https://manage.windowsazure.com. If you used the Express setup when configuring Azure AD on your App Service app, you can search for your Azure AD app using either your app name or the client ID of your Azure AD application. Once there, you will need to make two changes: 1) add the “Read directory data” delegated permission and 2) add a key to your Azure AD application.

enter image description here

If your app is already configured with the “Read directory data” and already has an existing key, then no further changes are necessary.

Step 2: Update App Service Auth Configuration via REST API

Next you need to update the App Service Auth settings for your web, mobile, or API app with your Azure AD key plus some additional login parameters. This is a little tricky because there is no official UI to assist with this. Until we get around to building that UI, I usually recommend that people use Azure Resource Explorer, using the following steps:

  • Search for your web, mobile or API app using the search bar.
  • Under your site node, navigate to /config/authsettings.
  • Click Edit to enable making changes.
  • Set clientSecret (a string property) to the key value that was generated in the Azure AD portal.
  • Set additionalLoginParams to the following:

(This is a JSON array value)

["response_type=code id_token", "resource=https://graph.windows.net"]
  • Click the Read/Write button at the top of the page to enable making changes.
  • Click the PUT button to save your changes.

The JSON configuration for your auth settings should look something like the screenshot below.

enter image description here

Once this is done, the next time users log into your web app, there will be a one-time prompt to consent to graph API access. Once consented, the App Service Auth infrastructure will start populating access tokens and refresh tokens into your app’s Token Store, which can be used for making Azure AD Graph API calls.

Calling the Graph API as the End-User

Once the app is properly configured, the code to obtain the token and call into the Azure AD Graph API using the user’s identity is relatively trivial. Here is a C# example of how to obtain the user’s profile photo from the Azure AD Graph from within your Web, Mobile, or API app:

// The access token can be fetched directly from a built-in request
// header! If this is null, it means you either haven't completed
// the setup prerequisites or you have disabled the token store in
// the Azure portal.
string accessToken = this.Request.Headers[
  "X-MS-TOKEN-AAD-ACCESS-TOKEN"];

// Call into the Azure AD Graph API using HTTP primitives and the
// Azure AD access token.
var url = "https://graph.windows.net/me/thumbnailPhoto?api-version=1.6";
var request = WebRequest.CreateHttp(url);
var headerValue = "Bearer " + accessToken;
request.Headers.Add(HttpRequestHeader.Authorization, headerValue);
 
using (var response = request.GetResponse())
using (var responseStream = response.GetResponseStream())
using (var memoryStream = new MemoryStream())
{
  responseStream.CopyTo(memoryStream);
  string encodedImage = Convert.ToBase64String(
    memoryStream.ToArray());

  // do something with encodedImage, like embed it into your HTML...
}

The above example is intentionally trivial, but you could imagine customizing it to use other Azure AD Graph APIs, including group membership APIs for building your own security group ACLs. I’ll also point out that I used HTTP primitives rather than using the official Graph API Client SDK. This was mainly to emphasize that access to the Azure AD Graph API can be written in any language and doesn’t require any SDKs (though you can certainly use the SDKs if you like).

If you’d like more information on the available Azure AD Graph APIs, please consult the documentation on MSDN: https://msdn.microsoft.com/en-us/library/azure/hh974476.aspx. If you have any questions or are running into issues, I recommend posting them on StackOverflow and adding the tags azure-app-service and azure-active-directory. Also, be sure to reference this post in your question. I hope this is helpful!

Author: cgillum

Principal Software Engineer at Microsoft.

25 thoughts on “App Service Auth and the Azure AD Graph API”

  1. Hi – Another great article and I’m so close to getting it to work. I’ve added permissions to the AAD and updated the settings under Auth. However I’m getting “The remote server returned an error: (401) Unauthorized.”

    I’m using a win 10 universal app so the code is slightly different and I’m just trying to return basic user info.

    var url = “https://graph.windows.net/me/?api-version=1.6”;
    var request = WebRequest.CreateHttp(url);

    var headerValue = “Bearer ” + myDataManager.token();
    request.Headers[HttpRequestHeader.Authorization] = headerValue;

    var response = await request.GetResponseAsync();

    1. It’s hard to say what the issue could be without some kind of network trace. Typically a 401 would indicate that you’re not sending a token. It could also mean you’re sending the wrong token. Check and see if there is a response payload and whether any details can be found there.

  2. Hi Cgillum, I need to do this so that I get the refresh_token back. Tried accessing https://resources.azure.com/ but the Search bar does not work for me. I tried searching for the app name I have created before. Any clue? Is there a Rest endpoint I can invoke via PostMan to get it done?

    Thanks
    pallab

    1. Interesting. Perhaps a permission issue? You could try hitting the REST endpoint directly. If you’re on Windows, I recommend ARM Client. Once you log in, you can run the following command (be sure to fill in the appropriate values for {subscription}, {resource-group}, and {site-name}):

      armclient PUT https://management.azure.com/subscriptions/{subscription}/resourceGroups/{resource-group}/providers/Microsoft.Web/sites/{site-name}/config/authsettings?api-version=2015-08-01 "{\"properties\":{\"additionalLoginParams\":[\"resource=https://graph.windows.net\",\"response_type=code id_token\"]}}"

  3. Great article. Not much out there that I can find discussing how to setup auth.

    I would like to implement the above, but for a multi-tenant MVC web app (not mobile) that also access the new Microsoft Graph endpoint (unified). Unfortunately, when I put “code” in the “response_type=code id_token” it fails. I suspect that the backend is looking for a Tenant-Id or not putting in “common”.

    Any advice on how to set this up.

    Also, where can I find information on “allowedExternalRedirectUrls”

    1. Thanks Jeff. As for getting multi-tenant authorization to work, try following the steps in this blog post to see if that helps. As always, check your application logs if you need more information on auth-related failures.

      Regarding allowedExternalRedirectUrls, this is a list of URLs to which we allow redirecting to after login/logout. It’s primarily intended for mobile scenarios. Adrian Hall discusses it a bit in his blog post on using Azure AD with Azure Mobile Apps.

    2. Thanks for the reply. I had already followed the linked article and it works, but I noticed that the bearer token was not in .auth/me. So after looking at my http headers, I notice that the only token stored in the token store was the id_token.

      So, not being able to get an access token because the token store is intercepting my post returns, I turned to your post.

      I suspect that “code” is required to get the access token and that this fails causing an internal server error because the azure auth is not aware of my user tenantId.

      If you know of another work around, would love to hear it. otherwise, will stick with my own auth setup -but would prefer to ditch that overhead.

    3. Thanks Jeff for this information. We still have some work to do in order to make multi-tenant applications a good first-class scenario. It’s on our to-do list, but haven’t had a chance to get it done yet. I’ll make a note of this problem that you’re running into to make sure we get it covered.

    4. Would like to commend that the above solution now appears to work in a multi-tenant configuration.

      I was also able to use Microsoft Graph in place of Azure AD Graph in the above.

      Anyone have recommendations on how to conduct local debug on an app that uses this type of external authentication. For mobile apps, I know that there is middleware. I haven’t found anything for webapps.

  4. Can I call onto the Graph API if I’m using Azure B2C? I’ve followed the steps in this article (and previous ones) and I’ve got b2c setup as well as EasyAuth for my app services website. However, when I try to get hold of the access token here

    string accessToken = this.Request.Headers[
    “X-MS-TOKEN-AAD-ACCESS-TOKEN”];

    it just returns null. There is a value set for X-MS-TOKEN-AAD-ID-TOKEN though.

    thanks

    1. Nice, thanks for the link to the docs. I had not yet looked into this scenario, but I’m glad to know it can be made to work. 🙂

  5. One more question:

    I am using easy auth in a non-mobile web app.

    Can you recommend a sample or point me to an article that would allow me to conduct local debugging? Everything I am doing requires Microsoft Graph auth. So, I can’t really debug unless I litter my app with authentication code. Would prefer not to.

    I know that for mobile, middleware is available. Curious if there is anything else out there that would do the trick.

    1. Unfortunately we don’t have a local debugging solution for web apps. For debugging Graph API calls, my suggestion would be to put all your Graph API logic into a library that you can test locally. The input to the routines would be an access token which can be used to access the Graph API. You can either use ADAL to produce these access tokens or you can log into your web app and download them from the built-in /.auth/me endpoint.

    2. One more question.
      Let’s suppose that after authentication/authorization, I now want to get a token for SharePoint. I first use the graph api to get the sharepoint endpoint. Next I need to get a SharePoint token.

      Here is where things fall through – I want to utilize the azure active directory nugget package and AuthenticationContext/AuthenticationResult. Normally, I would have a token cache in a db or redis cache; however, now we are using azure token cache.

      Any examples out there that use the Azure Token Cache in the AuthenticationContext class?

      ie. something like AuthenticationContext authContext = new AuthenticationContext(authority, [Azure Token Cache]);

  6. Hi, I’m trying to use easy auth from an iOS client xamarin native app using the MobileServiceClient.LoginAsync(view, provider), this signs me in successfully and returns a MobileServiceUser with a user id and token populated. When i subsequently use MobileServiceClient.InvokeApiAsync(“.auth/me”, HttpMethod.Get, null) with the same service which already has an authenticated user populated, it gives me 401 Unauthorized, when i navigate to the .auth/me url for me web service’s url in the browser it shows the user profile just fine, but from mobile client it doesn’t work, any idea what is missing here? I checked the X-ZUMO-AUTH header value and it is being sent in the request populated with the token i received after calling LoginAsync. Any help will be greatly appreciated.

    1. One thing to add to what I described, when I call my custom web APIs using the same method they return data just fine and are recognized as authorized, so is this an azure active directory specific authorization? I’m a bit confused with this process and what I need to do to just get basic user information from Azure Active Directory using this “simple” method.

    2. Hi Dmitry. I would not expect you to get a 401 Unauthorized response, but I would expect you to get a 404. The InvokeApiAsync method is internally prepending your URL paths with “/api”, so instead of requesting /.auth/me, it’s requesting /api/.auth/me which doesn’t exist. If you instead use MobileServiceClient.InvokeApiAsync(“/.auth/me”) – notice the “/” at the beginning – then the request should succeed. If you’re still getting a 401 response, try enabling application logging to see if there is any more information about why the request was rejected as unauthorized.

  7. Hi, thank you for your reply, I forgot to mention that I already ran into this pre-pending and ended up overriding the DelegatingHandler for the MobileServiceClient and just stripping the “/api” out for this request, so it is actually requesting “/.auth/me” but thank you for pointing out this convention, I will use it.

    I’ve narrowed down the issue to when I’m trying to make requests using the MobileServiceClient using an auth token received during a prior session using MobileServiceClient.LoginAsync(view, provider). I securely store this token in the iOS keychain, then retrieve during a new session to use it to make calls to api endpoints. I am trying to avoid the user from having to authenticate using their username/password every time they launch the app akin to how all bank/credit card apps do it after the initial user signin. They use TouchID to authenticate there after. In this scenario I am populating the auth token and user id on the MobileServiceClient.user before I make any api requests. Could it be that the token is expiring and I’m getting Unauthorized? I saw some posts talking about it expiring often, is there a way to set the expiration date for the Azure AD auth tokens if this is the case? How can I either refresh them in the background or set their expiration date to be a much longer interval?

    Really appreciate any and all your help,

    Thank you again!

    1. Yes, it’s very possible that the token is expiring. By default, Azure AD tokens expire after one hour, so the mobile service authentication tokens will have the same one hour lifetime. There are two ways you can fix this: 1) configure longer token lifetimes in AAD. More information on how to do this can be found here. Alternatively, you can use the token refresh capabilities of App Service, which are described here.

  8. I wanted to contribute to the community. I have been trying to access both the Microsoft Graph and SharePoint APIs using EasyAuth in my WebApp. I finally figured this one out.
    1. Without following the procedure to set [“response_type=code id_token”, “resource=https://graph.windows.net”], you will always get the [“X-MS-TOKEN-AAD-ID-TOKEN”]
    2. Install Microsoft.IdentityModel.Clients.ActiveDirectory from NUGET.
    3. Then you can pull on demand your Access Codes to any API you have granted permission to in Azure AD using this code:
    string IDToken = this.Request.Headers[“X-MS-TOKEN-AAD-ID-TOKEN”];
    AuthenticationContext authContext = new AuthenticationContext(String.Format(“https://login.microsoftonline.com/{0}”, tenantId));
    UserAssertion assertion = new UserAssertion(IDToken);
    ClientCredential cred = new ClientCredential(clientId, clientSecret);
    AuthenticationResult authResult = await authContext.AcquireTokenAsync(resource, cred, assertion);

    That’s it. authResult will have your Access Token for the resource.

    Now, to conduct local debug, all you need is the ID Token. Just check if the ID Token is available, if not, get it from somewhere. I just use a published webapi that I am logged into and call it to get the ID token.

    I hope this helps someone because I have wasted too many hours trying to figure out how to get around the requirement to cache tokens.

    It would be very helpful if we could add multiple resources to the token store to cache each resource token; however, it does not appear possible.

    Of course, with Microsoft Graph API Ver 2, you can access pretty much everything – so multiple resources will not be necessary in most cases.

    I have found the above to be significantly faster than having my application conduct authentication/authorization.

  9. Chris,

    Most of my problems with App Service authentication revolve around local v. remote debug. An asp.net core app would allow you to have two different authentication schemes, one for debug, and one for azure deployed. If one were to add the appropriate headers in debug, this would be a very simple way to “simulate” the deployed environment.

    However, it appears that one must setup an asp.net core app for authentication with azure AD. The [Authorize] attribute does not work like it did under the older asp.net.

    Would be tremendously helpful if Microsoft would publish a single asp.net core sample that uses app service authentication (not mobile).

  10. Thank you…. Thank you…. Thank you…. I have been trying to figure your how to get Graph Api working from with Azure App deployed in Azure….and this article helped me more than any other article…..
    Thank you once….Could not thank you enougth……

Leave a Reply