Microsoft Graph API and .NET Core

Graphs are awesome and a great way of showing trends. However, this post is about a different sort of graph, not the worrying one above. This is a post on the Microsoft Graph API and how to use it with .NET Core.

The Microsoft Graph API is a unified API that MS are slowly migrating their existing ones into, to create one monolithic API (to rule them all?). The Graph API includes Office 365, Outlook/Exchange, SharePoint and Teams APIs. Some APIs are still separate, such as Skype for Business and Azure DevOps (the re-branded VSTS build and release APIs).

MS APIs

You can try out the REST endpoints with the Graph Explorer. However, this asks for a lot of permissions to use it (and more later) and there is no obvious way to revoke them, so I’d use a dedicated test account.

graph explorer permissions

I’m more interested in using .NET Core to access these APIs and there are Microsoft.Graph NuGet packages that help with this. Unfortunately, they are not quite finished and there are many things you can do directly with the HTTP API that you can’t do with the SDK package yet. The API uses MSAL for auth and there is a pre-release Microsoft.Graph.Auth package to add this to the Graph package.

To call the APIs we need to set up the permissions in the Azure Active Directory admin center and configure our “App registrations”. The first step after selecting the Graph API is to choose between delegated and application permissions. The correct choice depends on the type of application you are building, e.g. an interactive web application or background process.

delegate or application

You can then select what permissions you want granted. It’s best to limit this to the smallest set that you need.

API permissions

If using application permissions then you will need an admin to grant consent to your request. You should also configure a certificate, which is more secure than a simple shared secret.

API certificate

There are a few quickstart guides available in the web console including web and daemon examples for .NET Core.

API quickstart guides API quickstart guide .NET Core web API quickstart guide .NET Core daemon

These samples demo the delegated and application flow initialisation but they don’t use the Graph API NuGet package, as they call the REST API directly. They do use the identity package for auth though.

Errors

When giving these samples a kick you may hit the following errors.

401 Unauthorized

Failed to call the Web Api: Unauthorized

"error": {
  "code": "Authorization_IdentityNotFound",
  "message": "The identity of the calling application could not be established.",
  "innerError": {
    "request-id": "c02c02c0-2c02-c02c-02c0-2c02c02c02c0",
    "date": "2019-09-20T09:01:21"
  }
}

Authorization_IdentityNotFound

This means that you haven’t authenticated correctly, perhaps because of not configuring or registering the certificate correctly.

403 Forbidden

Failed to call the Web Api: Forbidden

"error": {
  "code": "Authorization_RequestDenied",
  "message": "Insufficient privileges to complete the operation.",
  "innerError": {
    "request-id": "c02c02c0-2c02-c02c-02c0-2c02c02c02c0",
    "date": "2019-09-20T09:10:41"
  }
}

Authorization_RequestDenied

This means you have got a step further but either haven’t selected the correct permission or it hasn’t been granted by an admin yet. Be careful of altering permissions as you may require re-approval.

Certified Secret

While using a client secret may be easiest and OK for development, it’s best to use a certificate for production. It makes sense to do this from the start so that you don’t have two ways of doing things and it gets you into secure practices.

It’s pretty straightforward to generate a self-signed certificate for this, if you have the latest version of Windows. Unfortunately, older versions don’t have the required parameters.

For example, run the following in an admin PowerShell console to generate a certificate valid for 15 years. You can revoke this easily, so it’s not like issuing one for the web where the validity should be shorter.

$cert=New-SelfSignedCertificate -Subject "CN=MsGraphApiCert" -CertStoreLocation "Cert:\LocalMachine\My" -KeyExportPolicy Exportable -KeySpec Signature -NotAfter (Get-Date).AddYears(15)

Cert:\LocalMachine\My stores the cert at the machine level but you can put the cert in the user’s store instead. The demo app uses StoreLocation.CurrentUser, so you may need to change this.

Then you can use MMC to export the public key as a DER .cer file and upload it to the AAD portal. However, when you run your app you may get the following error thrown.

WindowsCryptographicException: Keyset does not exist

This may mean that you need to grant read access to the cert (via the UI or terminal) for the account running the app.

Limitations

There are many limitations to the API and SDK. It doesn’t feel all that joined up currently and it’s worth reading the known issues page for a subset of the problems.

For example, certain properties are only available when you retrieve a single object and are not present when getting multiple objects of the same type.

Certain properties cannot be returned within a user collection. The following properties are only supported when retrieving an single user: aboutMe, birthday, hireDate, interests, mySite, pastProjects, preferredName, responsibilities, schools, skills, mailboxSettings.

Some properties are available on the API but not in the SDK, for example createdDateTime on a user. In this case you will need to use the REST API directly, without the SDK package (like the example apps do).

You may need to use the API beta endpoint for some calls, such as people and rooms. These may move to the stable endpoint in the future.

In summary, it’s a useful API if you need the data it provides but in places it seems a little unfinished and inconsistent.


This blog is treeware! If you found it useful then please plant a tree.
Donate a treeDonate a tree🌳🌳