Export (0) Print
Expand All

Using the Graph API to Query Azure AD

Updated: May 12, 2014

NOTE: This sample is outdated. Its technology, methods, and/or user interface instructions have been replaced by newer features. To see an updated sample that builds a similar application, see WebApp-GraphAPI-DotNet.

This sample application is intended for .NET developers who want to add to existing applications and build new applications for Windows Azure Active Directory (Windows Azure AD). This walkthrough builds on the Adding Sign-On to Your Web Application Using Azure AD, which produced a sample app that demonstrates how to provide a web single sign-on user experience for Windows Azure AD customers. This walkthrough shows how to use the Windows Azure AD Graph API to read directory data. The Graph API is a RESTful API that allows applications to access customer Windows Azure directory data.

Applications need access to directory data for many scenarios, including:

  • Retrieving lists of users, groups, contacts for people/group pickers

  • Reading detailed tenant, user, and group information

  • Verifying group membership

  • Modifying user, groups, and group membership

  • Updating a user passwords

  • Disabling user accounts

When a multi-tenant application tries to acquire a token to access the Graph API for an Azure AD tenant that has recently consented to the application, the token request might fail with error ACS50012. To resolve the problem, wait a few minutes and try again. Or, have the tenant administrator who provided consent log on to the application after consenting. For more information, see ACS Error Codes.

This document is organized into the following sections:

This following prerequisites are required to complete this tutorial:

At the end of this walkthrough, you will have an application that is configured to read data from your Azure AD tenant. The application can read the following directory entities: Users, Groups, Contacts, Company Information, Licenses, and Roles; and, if your application is granted write permissions, it can also update the entities.

In this sample application, we’ll review how to read directory data from your Azure AD company. Additional advanced topics include:

  • Getting full user details

  • Creating and updating users

  • Getting a list of groups

  • Updating group membership

The single sign-on experience remains the same after you update this application so that it can access the Graph API. After successful user authentication, the application requests a token from Azure AD authentication endpoint, and if successful, the app uses the token in calls to the Graph API to get all users from the tenant. The application displays a list of users, showing their Display Names and User Principal Names.

Solution Architecture

In this walkthrough, we will be using the OAuth 2.0 Client Credential flow to authenticate the application. Before accessing the Graph API endpoint, the application must first acquire a valid token from Azure AD’s authentication endpoint -- it does this by presenting valid application credentials (client ID and secret). If the credentials are validated, a signed token is returned to the application. Thereafter, the application includes the token in the Authorization header of its calls to the Graph API. The Graph API service validates the token against the incoming request, and if it passes, an authorization check occurs next.

Application authorization is verified by the Graph API and its underlying Role Based Access Control (RBAC) service. Calls to the Graph API are limited by the application's permissions. Data is returned to the application if authentication and authorization pass.

An application’s authentication and authorization configuration are stored in Azure AD using a Service Principal object stored in tenant directory. Applications are represented in Azure AD by a Service Principal object with a unique identity, credential, and permissions. This is similar to the User Principal objects in Active Directory that represent users, each having unique identities, credentials and permissions.

An application’s Service Principal has a unique ID and secret that is used for authentication. Authorization is managed by adding the application’s Service Principal to a role that has the required permissions. Tenant administrators can create application Service Principals and adding them to roles in the Azure AD Management Portal. Optionally, Tenant administrators can also use Windows PowerShell to manage Service Principals. For more information, see Manage Azure AD using Windows PowerShell

In the Adding Sign-On to Your Web Application Using Azure AD walkthrough, you authorized the application to allow single sign-on using your Azure AD user credentials by configuring the app permissions in the Azure AD Management Portal. You will now update the application configuration to enable your Expense Reporting application to authenticate to, and be authorized to call, the Graph API. We will perform the following steps:

  • Authorization: Configure your app permissions to allow read/write access to the directory.

  • Authentication: Get an application key, which is your application’s password. It is used to authenticate your application to the Graph API.

  1. Go to the Microsoft Azure Management Portal (https://manage.WindowsAzure.com), sign in, and then click Active Directory. (Troubleshooting tip: "Active Directory" item is missing or not available)

  2. Click to select your directory, click Applications, and then click the Expense Reporting sample application you created in the single sign-on walkthrough.

    External Access

  3. At the bottom of the page, click Manage Access.

  4. Select Change the directory access for this app.

    What do you want to do?
  5. Select Single Sign-on, Read Directory Data. Then, click the checkmark to save your changes.

    Directory access

  1. On the Expense Reporting application page, expand Enable your app to read or write directory data. In the Create a Key section, select Configure key.

    Configure Key

  2. To add a key, on the Configure page, in the Keys section, select the key’s lifespan (default 1 year), and then click Save at the bottom of the screen. This generates a key value that is your application’s password.

    The key value is displayed after key creation, but it cannot be retrieved later. Therefore, you should immediately copy the key value and store it in a secure place for your future reference. Also, your application can have multiple keys –- for example, you may want one or more for testing and production.

    Graph key

At this point you have a Client ID (Application ID), an application key (the key value) and have configured read permissions for the application.

In this walkthrough sample application, we are using the key value as a password to authenticate the application. In OAuth 2.0 terms, are using the Client Credentials Grant flow, where grant_type=client_credentials).

Open Visual Studio, then open "Expense Reporting," the single sign-on walkthrough project that you previously built. We will be modifying the sign sign-on walkthrough application in the following steps:

  1. Add the Graph helper class project

  2. Update to WCF Datservices 5.3 or greater

  3. Update the Web.config file

  4. Modify the HomeController

  5. Add a new View for Users

  6. Update the common _Layout View

Download the Azure AD Graph API Helper Library. The Graph Helper class project includes a library and classes that facilitate authenticating to and calling the Graph API. It includes source code and should be included and built as part of this walk-through.

  1. To add the Graph Helper to the Expense Reporting project, right-click the Solution 'ExpenseReport' solution, click Add, then click Existing Project.

  2. From the Add Existing Project dialog, navigate to the Graph Helper path, then open the Microsoft.WindowsAzure.ActiveDirectory.GraphHelper.csproj project file.

The Graph Helper project is now added to your ExpenseReport solution.

The appSettings section of the Web.config file has application specific configuration information – add the ClientId and Password key-value pairs to the application’s Web.config file.

  • ClientId: equal to the Client ID value from the Azure AD Management Portal application management page.

  • Password: equal to the Application Key Value from the Azure AD Management Portal Application management page. This should have been recorded from the previous step to create a key – note this is not retrievable. If you forgot or lost the previous key, create another under the same application.

    <add key="ClientId" value="<insert your ClientId here>"/>
    <add key="Password" value="<insert your Application Key here>"/>

After making the changes, save the Web.config file.

  1. In Visual Studio, right-click the Expense Reporting project References folder and then click Add Reference…

  2. In the Reference Manager dialog, click Extensions and then select Microsoft.Data.OData version assembly and the Microsoft.Data.Services.Client version assembly.

    OData Reference
  3. In the same Reference Manager dialog, expand the Solution menu on the left, then click the checkbox for the Microsoft.WindowsAzure.ActiveDirectory.GraphHelper. Press OK, then the references will be added to your project.

    Add Graph Helper Reference

Open the HomeController.cs file, which is in the Controllers folder. Add the following assemblies to the file, then save the file.

using System.Configuration;
using System.Security.Claims;
using System.Data.Services.Client;
using Microsoft.WindowsAzure.ActiveDirectory;
using Microsoft.WindowsAzure.ActiveDirectory.GraphHelper;

Find the HomeController class in the HomeController.cs file, where the existing ActionResults reside (Index, About, Contact). Add a new ActionResult called Users as shown below:

       public ActionResult Users()
            //get the tenantName
            string tenantName = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;

            // retrieve the clientId and password values from the Web.config file
            string clientId = ConfigurationManager.AppSettings["ClientId"];
            string password = ConfigurationManager.AppSettings["Password"];

            // get a token using the helper
            AADJWTToken token = DirectoryDataServiceAuthorizationHelper.GetAuthorizationToken(tenantName, clientId, password);

            // initialize a graphService instance using the token acquired from previous step
            DirectoryDataService graphService = new DirectoryDataService(tenantName, token);

            //  get Users
            var users = graphService.users;
            QueryOperationResponse<User> response;
            response = users.Execute() as QueryOperationResponse<User>;
            List<User> userList = response.ToList();
            ViewBag.userList = userList;

            //  For subsequent Graph Calls, the existing token should be used.
            //  The following checks to see if the existing token is expired or about to expire in 2 mins
            //  if true, then get a new token and refresh the graphService
            int tokenMins = 2;
            if (token.IsExpired || token.WillExpireIn(tokenMins))
                AADJWTToken newToken = DirectoryDataServiceAuthorizationHelper.GetAuthorizationToken(tenantName, clientId, password);
                token = newToken;
                graphService = new DirectoryDataService(tenantName, token);

            //  get tenant information
            var tenant = graphService.tenantDetails;
            QueryOperationResponse<TenantDetail> responseTenantQuery;
            responseTenantQuery = tenant.Execute() as QueryOperationResponse<TenantDetail>;
            List<TenantDetail> tenantInfo = responseTenantQuery.ToList();
            ViewBag.OtherMessage = "User List from tenant: " + tenantInfo[0].displayName;

            return View(userList);

Create a new view under the Views/Home folders called Users.cshtml, and add the following code:

@model IEnumerable<Microsoft.WindowsAzure.ActiveDirectory.User> 
    ViewBag.Title = "Users";


@if (User.Identity.IsAuthenticated)

  foreach (var user in Model) {
         @Html.DisplayFor(modelItem => user.displayName)    
         @Html.DisplayFor(modelItem => user.userPrincipalName)

In the Views/Shared folder, open the _Layout.cshtml file . In the <header> section of the file, in <nav> element, add the new list item: "<li>@Html.ActionLink("Users", "Users", "Home")</li>". Then, save the file.

                        <ul id="menu">
                            <li>@Html.ActionLink("Home", "Index", "Home")</li>
                            <li>@Html.ActionLink("About", "About", "Home")</li>
                            <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
                            <li>@Html.ActionLink("Users", "Users", "Home")</li>

To run the application, press F5. When prompted, sign in with the credentials of a user in your Azure AD directory, that is, a user with an organization account in the domain of your directory.

The single sign-on experience is the same as you saw in the previous walkthrough, requiring authentication using your Azure AD credentials. If you published your application to a website, you should update it with the updates from this walkthrough. After successful user authentication, select the Users tab from the top right menu.

Display Users

The application starts the process of calling the Graph API by first requesting a token from Azure AD Authentication endpoint. Once this is successful, it will use the token in the subsequent Graph call to get all users from the tenant. The application will then display a list of users, showing their Display Names and User Principal Names.

This concludes the coding for the Graph API walkthrough application. The next section includes more detailed information and links to a more advanced Graph API sample application that shows additional read and write operations.

After successful single sign-on, the application will request a token from the Azure AD Authorization endpoint, using the tenant name (obtained from the signed on user’s tenant ID claim), ClientID and Password to authenticate. The details of the method that supports the token acquisition can be found in the DirectoryDataServiceAuthorizationHelper class found in the file of the same name. The GetAuthorization method manages acquiring the JSON Web Token (JWT) token from Azure AD Authentication by providing a valid tenant name (any verified domain owned by the tenant), Client ID and the Password.

A successful request will return a JWT token to be used in calls to the Graph API, which is inserted in the Authorization header of subsequent requests. The Graph API call to get all users is an HTTP GET request that contains the following headers:

Content-Type: application/json; odata=minimalmetadata
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1T….

It is recommended that the JWT token be cached by the application for subsequent calls – in the sample application, the JWT token expiration is checked before making a second Graph API call. If the token is expired, then a new token is acquired. If a call to the Graph API is made with an expired token, the following error response will be returned, and the client should request a new token.

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="contoso.com", error="invalid_token", error_description="Your access token has expired. Please renew it before submitting the request.", 

Currently there is a preview of Azure Authentication Library (AAL) which manages the acquisition of the Azure AD authentication tokens. When AAL is released, we will update our sample applications and documentation to use AAL. The documentation for the AAL preview is located here.

Additional REST calls, including read and write methods, can be found in another MVC4 Sample application that can downloaded from here.

This sample demonstrates additional REST functionality including:

  • Get and Set User Details, including thumbnail photos

  • Create, Update Groups

  • Update Group Membership

  • Paging for handling a large number of returned objects

Community Additions

© 2014 Microsoft