Understanding Azure Active Directory Graph Operations
We mentioned in the last post that AAD Graph is a RESTful service implemented using the OData protocol. We also provided a high level overview of RESTful services and OData protocol. In this post, we will try to provide deeper insights into the operations supported by the Graph service and how to invoke these operations.
AAD Graph Service is a multitenant service which means that the service supports multiple tenants/organizations. When you connect to the service for accessing the information, you need to provide the name of the tenant you would like to work with. For this post, we will use a Demo tenant (GraphDir1.OnMicrosoft.com) that exists in AAD. You can use the Graph Explorer tool for trying out the examples in this post against this demo tenant.
Required HTTP Request Headers and Query Parameters
All operations on Graph service can be done using standard HTTP operations like Get, Post, and Delete etc. We will see plenty of examples of what the request and response data will be for various operations. But all these HTTP requests are also required to specify one HTTP header (Authorization) and one Query parameter (api-version) in the request. Let's look at what those are.
- Authorization header: Any application that’s accessing graph data should present a token that authorizes access to the Graph data for a tenant. We will look at how to fetch this token value and pass it in Authorization header in later posts when we start building sample applications. For now, the most important thing is to understand the URL patterns for accessing various resources in AAD Graph and the data that you will send and will receive for various operations. The name of the header is "Authorization" and the header value will be something like below.
Authorization: Bearer eyJ.............................................Hg
- api-version query argument: You need to specify the version of the Graph service resource you want to access. The service version information must be specified as a query parameter with name ‘api-version’ . The value will look something like below.
https://graph.windows.net/GraphDir1.OnMicrosoft.com/users?api-version=2013-04-05
Now we are ready to look at how to do various data access and manipulation operations on the Graph service. Let’s start with the Service root document and drill down into the details.
Accessing Graph Service Root
The service root lists the set of Resource collections that are exposed by the AAD Graph service. As you can see from the response, the Resource collections (also referred to as feeds) exposed by AAD Graph service includes Users, Contacts, and Groups etc.
Request URL:
HTTP Method: GET
Response:
Accessing Resource Collection
You can construct the URL for accessing a specific Resource collection, for example users, by appending the name of the Resource collection to the service root URL. Let’s take the example of accessing the users resource collection. You can see that the response is an array of JSON objects (of length 2 in this case). The response has been trimmed down by removing some properties so that it is more readable.
Note: The first line in the response below which is the “odata.metadata” property provides information on how to access additional metadata for this response pay load if you need to. If you go to the URL below, you will see an Xml document that describes the metadata for the collections exposed by this service. You can read all about this Xml format here. In most of the applications, you will be looking at just the data part of the response and thus will ignore this property value.
Request URL:
https://graph.windows.net/GraphDir1.OnMicrosoft.com/users?api-version=2013-04-05 |
HTTP Method: GET
Response:
{ "odata.metadata": "https://graph.windows.net/GraphDir1.OnMicrosoft.com/$metadata#directoryObjects/Microsoft.WindowsAzure.ActiveDirectory.User" "value":[ { "objectId": "e428a9cb-7550-4991-afc3-48fe8b60be33", "accountEnabled": true, "city": "Seattle", "displayName": "Adam Barr" }, { "objectId": "bafb9fea-d7f3-4cec-af6a-bca2b553e83b", "accountEnabled": true, "city": null, "displayName": "Admin", } ] } |
Accessing specific Resource using Key value
Every OData Resource (also referred to as entry) has one or more properties that are annotated as the Key property in the metadata definition. Each Resource in the Resource collection can be uniquely identified in that collection given the value of the key property. For AAD Graph Service, ObjectId property acts as the Key property for all Resource types.
You can access a specific Resource in a collection by appending the key value in the segment following the resource collection name. For users resource alone you can specify either the objectId of the User or the userPrincipalName of the user as the key value. In the below example, we are using userPrincipalName property value as the key value.
Request URL:
HTTP Method: GET
Response:
{ "odata.metadata": "https://graph.windows.net/GraphDir1.OnMicrosoft.com/$metadata#directoryObjects/Microsoft.WindowsAzure.ActiveDirectory.User/@Element", "objectId": "e428a9cb-7550-4991-afc3-48fe8b60be33", "accountEnabled": true, "city": "Seattle", "displayName": "Adam Barr" } |
Navigating to related resources through link properties
As the name suggests, AAD Graph exposes a Graph of objects interconnected via links. An entry in Graph Service can have two types of link properties - one which links it to at most one entry (example: manager property on User) and the second which links it to a collection of entries (example: directReports property on User).
For Single Valued Links
Let’s try to navigate to the manager for the User entry we retrieved in the previous section. "manager" is a single valued link since there can be at most one manager for a User. The first thing you need to find is the name of the navigation property that you would want to navigate. You can find this information in the Metadata document for Graph service at: https://graph.windows.net/GraphDir1.OnMicrosoft.com/$metadata . In this document, find the EntityType whose name is DirectoryObject. If you look at the list of the properties in this type, you can see that there are three navigation properties: manager, directReports and memberOf. The User type derives from DirectoryObject and thus inherits all the properties from DirectoryObject including these navigation properties. Now that we know the navigation property name, it is just a matter of appending this property name to the URL of the entry to navigate to the related entry. So here is the example where we will retrieve the manager entry for the User retrieved in the previous example.
Request URL:
HTTP Method: GET
Response:
{ "odata.metadata": "https://graph.windows.net/GraphDir1.OnMicrosoft.com/$metadata#directoryObjects/@Element", "objectId": "0758e306-1951-4761-99cc-6aecbcdf3d00", "displayName": "Derek Brown", "mail": Derek@GraphDir1.onmicrosoft.com } |
For Multi Valued Links
Let’s try to find the groups and roles that the User entry we retrieved in the previous section is member of. "memberOf" is a multi valued link since there can be any number of roles and groups that a user can be member of. The access pattern for single valued and multi valued links is the same. The only difference is that the response for multi-valued links is a collection instead of a single object.
Request URL:
HTTP Method: GET
Response:
{ "odata.metadata": "https://graph.windows.net/GraphDir1.OnMicrosoft.com/$metadata#directoryObjects", "value": [ { "odata.type": "Microsoft.WindowsAzure.ActiveDirectory.Group", "objectType": "Group", "objectId": "f9d373df-b75b-49e3-8a83-0d5dc112ef4c", "description": null, "dirSyncEnabled": null, "displayName": "PureEmailDistributionGroup", "lastDirSyncTime": null, "mail": "PureEmailDL@GraphDir1.onmicrosoft.com", "mailNickname": "PureEmailDL", "mailEnabled": true, "provisioningErrors": [], "proxyAddresses": [ "SMTP:PureEmailDL@GraphDir1.onmicrosoft.com" ], "securityEnabled": false }, { "odata.type": "Microsoft.WindowsAzure.ActiveDirectory.Group", "objectType": "Group", "objectId": "1747ad35-dd4c-4115-8604-09b54f89277d", "description": "Uses in Washington State", "dirSyncEnabled": null, "displayName": "Wash State", "lastDirSyncTime": null, "mail": null, "mailNickname": "BposMailNickName", "mailEnabled": false, "provisioningErrors": [], "proxyAddresses": [], "securityEnabled": true } ]} |
Fetching the related resource URL using $links
For single valued links
Instead of retrieving the related object through navigation property, you can also retrieve just the URL of the related Object. The URL for fetching the related object’s URL is same as the URL for fetching the related object except in the case of fetching the URL we will have $links in between the URL for the Resource and the name of the navigation property. Going through the $links will fetch the URL of the link instead of the related object.
Request URL:
HTTP Method: GET
Response:
For multi valued links
The access pattern for navigating the links is the same for multi valued links( as single valued) but the response will be a collection of URLs instead of one. Let's navigate the memberOf link as an example.
Request URL:
HTTP Method: GET
Response:
Query Operations
OData specifies a set of query options that can be expressed via HTTP request parameters. These query options can be used to query a service for advanced query operations like top, filter etc. Let’s look at some examples here. You can find the complete documentation for Query options in OData here. Since the semantics of these query operations are well known, let’s just look at the URLs and responses.
Query Operation: Top
Description of the Operation:
Retrieve the top 1 User from the Users Resource collection. The response will include a next link property at the end whose value you can use to get the remaining resources that were not included in this response.
Request URL:
https://graph.windows.net/GraphDir1.OnMicrosoft.com/users?$top=1&api-version=2013-04-05 |
HTTP Method: GET
Response:
{ "odata.metadata": "https://graph.windows.net/GraphDir1.OnMicrosoft.com/$metadata#directoryObjects/Microsoft.WindowsAzure.ActiveDirectory.User", "value":[ { "objectType": "User", "objectId": "e428a9cb-7550-4991-afc3-48fe8b60be33", "accountEnabled": true, "city": "Seattle", "displayName": "Adam Barr" } ], "odata.nextLink": "Users?$skiptoken=X'445370740200….” } |
Query Operation: Filter
Description of the Operation:
Retrieve the list of Users from the users Resource collection whose displayName equals ‘Derek Brown’.
Request URL:
HTTP Method: GET
Response:
{ "odata.metadata": "https://graph.windows.net/GraphDir1.OnMicrosoft.com/$metadata#directoryObjects/@Element", "objectId": "0758e306-1951-4761-99cc-6aecbcdf3d00", "displayName": "Derek Brown", "mail": Derek@GraphDir1.onmicrosoft.com } |
At this point, we have covered most of the interesting access patterns for Graph service. Using these examples, you should be able to retrieve most of the information in Graph. Next let’s look at some examples for Creating, Updating and Deleting entries and links.
Creating an Entry
You can use a HTTP Post operation to create an Entry. The URL that you post to would be the collection URL of the resource collection to which the created entry needs to be added to. The body of the request should have the data for the entry you want to create. The object that was created by this request will be returned as response. If you look at the request, you will see that it only has 4 properties while response has many additional properties. This is because we sent only the required properties for the User entry while response included all properties of User entry including the ones that are not set or generated by the service. For example, note the objectId property of the entry in the response which was generated by the Service. For readability, we have trimmed down the properties shown in the Response.
Request URL:
https://graph.windows.net/GraphDir1.OnMicrosoft.com/users?api-version=2013-04-05 |
HTTP Method: POST
Request:
{ "displayName": "TestUser22", "userPrincipalName": “tuser22@GraphDir1.onmicrosoft.com”, "password": “XXXXXXXX” "accountEnabled": “True” }
|
Response:
{ "odata.metadata": "https://graph.windows.net/GraphDir1.OnMicrosoft.com/$metadata#directoryObjects/Microsoft.WindowsAzure.ActiveDirectory.User", "objectId": "ff7cd54a-84e8-4b48-ac5a-21abdbaef321", "displayName": "TestUser22", “objectType”: “User”, "mail": “null”, "userPrincipalName": “tuser22@GraphDir1.onmicrosoft.com” } |
Updating an Entry
You can use a HTTP Patch operation to update an Entry. The URL that you use is the URL of the entry that you want to update. The body of the request should have the updated data for the entry and optionally you can include other properties that have not changed. The Service will update the content of the entry based on the content in the message. The object that was updated by this request will be returned as response. Let’s update the User entry we just created in the previous example by updating the City value to Redmond. Again the Response data have been trimmed down to make it readable.
Request URL:
https://graph.windows.net/GraphDir1.OnMicrosoft.com/users/ff7cd54a-84e8-4b48-ac5a-21abdbaef321?api-version=2013-04-05 |
HTTP Method: Patch
Request:
{ "city": “Redmond” } |
Response:
{ "odata.metadata": "https://graph.windows.net/GraphDir1.OnMicrosoft.com/$metadata#directoryObjects/Microsoft.WindowsAzure.ActiveDirectory.User", "objectId": "ff7cd54a-84e8-4b48-ac5a-21abdbaef321", "displayName": "TestUser22", “objectType”: “User”, "mail": “null”, "userPrincipalName": “tuser22@GraphDir1.onmicrosoft.com”, "city": “Redmond” } |
Deleting an Entry
You can delete an entry by using HTTP Delete operation against the Entry URL. You don’t need to send any data in the request and you won’t get any data in the response back other than the HTTP success code if the delete succeeded.
Request URL:
https://graph.windows.net/GraphDir1.OnMicrosoft.com/users/ff7cd54a-84e8-4b48-ac5a-21abdbaef321?api-version=2013-04-05 |
HTTP Method: Delete
Adding a Link between entries
We saw in the example for navigating through links using navigation properties that the URL using $links can be used to get the URL for the related object( for a single valued link) or a collection of URLs of related objects( for multi valued links).You can add a new link by posting to the same URL and provide the URL of the entry you would want to link to as the request body. You won’t get any data back in the response other than the HTTP success code if the operation succeeded. Let’s see an example for adding link between a User entry and another User entry as the manager( single valued link) and add a User to a Group using members property on Group( multi valued link).
Note: You need to use “url” as the property name for the URL of the entry you would like to link to in the request pay load as shown in the example below.
Single Valued link:
Request URL:
https://graph.windows.net/GraphDir1.OnMicrosoft.com/users/Adam@GraphDir1.onmicrosoft.com/$links/manager?api-version=2013-04-05 |
HTTP Method: PUT
Request:
{ “url”: “https://graph.windows.net/GraphDir1.OnMicrosoft.com/users/ff7cd54a-84e8-4b48-ac5a-21abdbaef321" } |
Multi Valued link:
Request URL:
https://graph.windows.net/GraphDir1.OnMicrosoft.com/groups/1625fccb-5870-4a80-a031-b0ec656ca0c9/$links/members |
HTTP Method: POST
Request:
{ “url”: “https://graph.windows.net/GraphDir1.OnMicrosoft.com/users/ff7cd54a-84e8-4b48-ac5a-21abdbaef321" } |
Deleting a Link between entries
Single Valued Link
Deleting a link is very similar to deleting an entry. For single valued, you would send a HTTP Delete request to the URL of the link.
Request URL:
https://graph.windows.net/GraphDir1.OnMicrosoft.com/users/e428a9cb-7550-4991-afc3-48fe8b60be33/$links/manager?api-version=2013-04-05 |
HTTP Method: Delete
Multi Valued Link
For multi-valued link, the Delete request should be sent to the link that identifies the specific link we would like to delete since the link property it self would map to multiple links and delete would fail. The objectId of the instance of the object on the other end of the link( objectId of the User in case of members property) can be used to specify the specific link that needs to be deleted.
Request URL:
https://graph.windows.net/GraphDir1.OnMicrosoft.com/groups/1625fccb-5870-4a80-a031-b0ec656ca0c9/$links/members/8004b5fc-e0fe-b46f-8c136b32d6c0?api-version=2013-04-05 |
HTTP Method: Delete
What’s next?
We have seen how to access collections, entries in collections and navigate through the Directory Graph. We also have seen examples of using OData query syntax to perform some advanced query operations. We also saw the examples to create, update and delete entries and links. We could do all of this using standard HTTP operations. So if you are going to integrate the AAD Graph service into your application, all you need from your development platform is support for sending http requests and reading JSON response back. As the next step, let’s build a couple of sample applications (one in .Net using MVC and one in PHP) to understand what it takes to perform these operations on different platforms.
Comments
- Anonymous
December 14, 2013
Glad to find this information. Did you know it's really hard to find information on the Graph API in the standard documentation on MSDN? The "Getting started" document for WAAD on MSDN lists prerequisites (Eg, you must have an Azure account). And then nothing else. That's not getting started!I couldn't find a single discussion of a REST GET/PUT/POST/DELETE model on MSDN. I couldn't find a single document containing HTTP Request/Reply sample payloads. The information on using the API is here, in a blog post tucked in the corner of the internet, and also on stackoverflow. There are better ways to publicize and document an API. The REST Reference is too granular, too deep. Why not show a "hello world" REST app in the official doc? Anyway I'm glad you posted this. - Anonymous
October 21, 2014
Really great article. Helped me a lot. Thanks - Anonymous
August 22, 2015
Thanks for posting this article. Its really useful. The links in it (eg: query options in OData) seems to be broken can u pls fix them.