During a recent project where I was needing to integrate with a Microsoft Azure Intune environment to query for endpoint information, I was having a heck of a time getting proper tokens for use with the Graph API to query for endpoints. Here is the short and sweet to getting API tokens to work correctly and getting endpoint lists from the Graph API.
So first things first, there will be some information mentioned below that is “Known” information. Basically you just have to know it, otherwise good luck. I’m not sure how Microsoft assumes people get this information, because for me at least, it was definitely not clear and took a lot of back and forth to get the right information.
This also assumes that you know how to do some basic stuff in the Azure portal and know how REST requests and OAuth works to some degree.
Step 1: Get your OAuth 2 Endpoint
You can get your OAuth 2 endpoint URL from inside the Azure Portal (https://portal.azure.com/).
- Login to https://portal.azure.com/
- Navigate to Azure Active Directory
- Click on App Registrations
- Click on Endpoints in the top bar of the App Registrations
- Copy out the OAuth 2 Token
Step 2: Setup an Application Registration
After getting the OAuth information (or before), you will need to create an application registration that has access to whatever resources you need the client to be able to access. In my case I had to add Intune API permissions by creating an Application and then setting the Required permissions, and then creating an access key. These items are completed by using the “Required permissions” and “Keys” options in the Application Registration Settings.
When you create the key you will need to make a copy of the Key value. The value will be displayed once on creation and if you forget it or don’t save it, you will have to create another key.
For Step 3 you will need the Key value and the Application ID from the application you created.
Step 3: Get an OAuth Token
After you have the OAuth 2 endpoint and your client (application id) and secret (key) you will be able to get a security token from Azure Active Directory.
Below is an example CURL request.
curl -X POST \ https://login.windows.net/{{Tenant_Id}}/oauth2/token \ -H 'cache-control: no-cache' \ -H 'content-type: application/x-www-form-urlencoded' \ -d 'grant_type=client_credentials&client_id={{Application_ID}}&client_secret={{Secret_Key}}&resource={{Resource_id}}'
The key items in this are the {{Tenant_Id}}, {{Application_ID}}, {{Secret_Key}} and {{Resource_id}}.
The Tenant ID is the portion of your login URL between “https://login.windows.net/” and “/oauth2/token”. It is often a GUID, here is an example:
https://login.windows.net/adf1d4ea-953d-4246-b439-4cdcdaa2b29c/oauth2/token
The Application ID and Secret Key are the values gathered from your Application Registration and setup that you performed.
The Resource ID is a tricky one… It changes depending on the type of call you want to make. For querying the service endpoints list from the Azure Graph endpoint, you must use the value 00000002-0000-0000-c000-000000000000.
If you’ve done everything right, you should get a response back that looks something like this.
{ "token_type": "Bearer", "expires_in": "3599", "ext_expires_in": "0", "expires_on": "1494260966", "not_before": "1494257066", "resource": "00000002-0000-0000-c000-000000000000", "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiI..." }
Once you get the “access_token” for the Resource ID 00000002-0000-0000-c000-000000000000, you can use query the Graph API for the list of available endpoints.
Step 4: Querying for Available Endpoints
To get the list of available endpoints, you will fire off a query to a URL crafted like this.
https://graph.windows.net/{{TenantID}}/servicePrincipalsByAppId/0000000a-0000-0000-c000-000000000000/serviceEndpoints?api-version=1.6
The Tenant ID is the portion of the Login URL we mentioned above. In some cases it may be different or you can use alternate values, but generally the GUID from the OAuth 2 login URL is a sure bet.
The below is an example cURL to the Graph API.
curl -X GET \ 'https://graph.windows.net/adf1d4ea-953d-4246-b439-4cdcdaa2b29c/servicePrincipalsByAppId/0000000a-0000-0000-c000-000000000000/serviceEndpoints?api-version=1.6' \ -H 'accept: application/json' \ -H 'authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiI...' \ -H 'cache-control: no-cache'
This should return a list of available endpoints.
{ "odata.metadata": "https://graph.windows.net/adf1d4ea-953d-4246-b439-4cdcdaa2b29c/$metadata#directoryObjects/Microsoft.DirectoryServices.ServiceEndpoint", "value": [ { "odata.type": "Microsoft.DirectoryServices.ServiceEndpoint", "objectType": "ServiceEndpoint", "objectId": "51d64e6c-f609-4b9d-8292-2b5cbf03ad4e", "deletionTimestamp": null, "capability": "EBookMetadata", "serviceId": "0000000a-0000-0000-c000-000000000000", "serviceName": "EBookMetadata", "uri": "https://fef.msua05.manage.microsoft.com/StatelessEBookMetadataFEService", "resourceId": "9d321fe9-8343-40f9-941a-b6cc7b7f6551" }, { "odata.type": "Microsoft.DirectoryServices.ServiceEndpoint", "objectType": "ServiceEndpoint", "objectId": "41d268a7-2237-4e17-b8b5-3b547fb23eac", "deletionTimestamp": null, "capability": "StatelessWIPReportFEService", "serviceId": "0000000a-0000-0000-c000-000000000000", "serviceName": "StatelessWIPReportFEService", "uri": "https://fef.msua05.manage.microsoft.com/WIPReportServices/StatelessWIPReportFEService", "resourceId": "dc5042c3-8dbc-4c17-a6e1-980108565e98" } }
From the results, you can pull out the service URI for whatever service you wish. For Intune you will want to look for the NACAPIService.
Once you have the URI you want, you’ll need to request a new token like in step 3, only using the Resource ID https://api.manage.microsoft.com/ instead. That will get you an access token that is valid.
Notes
If you are getting access errors, or Authentication_MissingOrMalformed errors, it generally means the resource id that you used was incorrect.
Here is an example response from a query using a token with an incorrect resource id.
{ "odata.error": { "code": "Authentication_MissingOrMalformed", "message": { "lang": "en", "value": "Access Token missing or malformed." }, "date": "2017-05-08T16:28:41", "requestId": "610b443a-9a3c-4489-99a2-2724fa86dc72", "values": null } }