So, I guessed that sooner or later I’m going to want to need to access Microsoft Graph APIs from a HoloLens and I was writing some similar code for a different environment I thought I may as well combine the two and write it up. I have a few examples of using OAuth2 on this blog over the years with the most recent using ADAL (Azure Active Directory Auth Libraries) which comes in lots of different forms (see https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-authentication-libraries). These support Azure AD v1.0 but I’m much more interested in Azure AD v2.0 libraries Microsoft Authentication Library (MSAL) – https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-libraries . An advantage using Azure AD v2.0 is that we can log in with either a personal Microsoft Account or an Organization account and have an API respond by detecting which one we are using and return the appropriate data. This makes the code I need to write to access my cloud file storage the same for both account types and make it all much simpler. There are additional advantages such as better standardisation and dynamic scopes but I will leave that to the docs to explain. Instead I’ll just talk through how I used the MSAL in a HoloLens app.
Register the App
First go to https://apps.dev.microsoft.com/#/appList where you can register a ‘converged’ app (one that uses both account types). All I did for this one was register a new app, add a platform which I chose as ‘Native Application’ and made a note of the Application Id.
The MSAL library comes in the form of a Nuget package and since I am using Unity to author my HoloLens app I will set up a couple of things:
– I created a C# Holographic App using the Visual Studio templates you get when you download the HoloLens emulator and added the Nuget package to it. I built the app and looked in the output folder to get the right MSAL binaries for a UWP app
– I copied these into my Unity project inside a Plugins folder and I configured the Inspector properties of the binary to ‘not process’ and just to work for WSA.
(I also surrounded all referencing code with a #if !UNITY_EDITOR && UNITY_WSA #endif so it would only be compiled for the UWP app and not inside the editor).
I made a ‘note to self’ that if this was a real project I might put this behind an interface and create a mock implementation for the editor.
I also configured my Unity project to use Experimental .NET 4.6 support (see http://peted.azurewebsites.net/holograms-catalogueto-the-cloud/ for more details). This makes it possible to use the MSAL library and also some nice programming features such as async/await.
Some simple code to interface with the MSAL library would look like this:
Whilst this will get us quickly up and running it is somewhat incomplete. If we call something like this each time we run our app the user will need to authenticate each time which could involve multi-factor auth and whilst this could get tiring on any app typing characters on a HoloLens will get ‘old’ quickly. The MSAL helps us out with a couple of things; first, it keeps a User cache with tokens and also it will automate the process of getting a refresh token when our access token expires.
Note, if you don’t know these concepts all is revealed in the OAuth2 specification which you can see here https://oauth.net/2/
In general, to take advantage of these we can have our app persist a user id string which we can use to pass a user back to the MSAL library. Also, we can use the AcquireTokenSilentAsync library call which will attempt to get us back an access token without making any network calls. We can fall back to AcquireTokenAsync if this method fails which will have the user authenticate again. Once we have an access token we can unlock the Microsoft Graph API.
For this simple sample I will just use the Microsoft Graph (http://graph.microsoft.com/) to retrieve some email but of course we could use similar code to do quite a few other things: discover the user profile and a graph of colleagues/contacts, discover and work with files in the cloud, calendars, OneNote, etc. Here’s what the basic code looks like using HttpClient:
I then use JsonUtility (https://docs.unity3d.com/ScriptReference/JsonUtility.html) to deserialize the response string. I facilitated this by logging the response string to the console, copying it to the clipboard and using Visual Studio’s Paste Special > Paste as Json to create some C# classes. I also found that JsonUtility doesn’t like properties so I converted all of those to fields, set a Serializable attribute on each class and the the following worked:
var email = JsonUtility.FromJson<Rootobject>(respStr);
Unity HoloLens App
The final thing was how I put this into a HoloLens app. So, first I used the Mixed Reality Toolkit (https://github.com/Microsoft/MixedRealityToolkit-Unity) and used it to configure my project for HoloLens. Then I decided to use speech command to sign in and out (the easiest option to hook up).
To use speech recognition with the MRTK just have your MonoBehaviour implement the ISpeechHandler interface – mine looks like this:
Then just used 3D Text Meshes in my scene to display the output. In order to support the OAuth2 Authorization Code flow it is common to use a browser or embedded browser window to facilitate the redirects and communication involved. I’m not sure if there is a browser control I can use in a Unity app for this purpose, I guess there is but I used the option of making my app a UWP XAML app which enables me to get redirected to the 2D browser to facilitate the OAuth flow and I get returned to my 3D app when it is complete. I used a lot of logging as for some reason Visual Studio won’t let me debug the MRTK at the moment. Here’s a flow through the app:
– user uses app for the first time
– user says ‘Sign in’
– the flow starts and the user is prompted for their credentials
– once authenticated we get returned to the 3D app
– a call is made to the Graph API to get the top 5 email messages
– these are shown in a TextMesh
The code repo is here https://github.com/peted70/msal-hololens