If you’ve read my earlier post on authentication of actions invoked in a Microsoft Teams MessageCard, you’ve probably seen the only useful information we get in the user’s token is the Object Id (`oid`).

{
  "iat": 1560799130,
  "ver": "STI.ExternalAccessToken.V1",
  "appid": "48afc8dc-f6d2-4c5f-bca7-069acd9cc086",
  "sub": "bc6c3ca0-5acd-4cd4-b54c-f9c83925e7e3",
  "appidacr": "2",
  "acr": "0",
  "tid": "4b1fa0f3-862b-4951-a3a8-df1c72935c79",
  "oid": "b26c3c10-5fad-4cd3-b54c-f9283922e7e2",
  "iss": "https://substrate.office.com/sts/",
  "aud": "https://serverlessdevops.azurewebsites.net",
  "exp": 1560800030,
  "nbf": 1560799130
}

While this is nice, it doesn’t really tell us much.

However, because we have the object id, we can use this to query the Azure Active Directory to check up on who this user actually is and implement some authorization logic with it.

However, when I was searching for a workable piece of code describing how to access AAD and retrieve users from it, the information was…not very useful. In the end, I have found something workable and I’ll be sharing my solution in this post.

How to set up my application in AAD

In order to do something inside AAD, you need to have an identity over there. Since we’re creating an application (console or API), we need to create an Application Registration.

To do this, navigate to your Azure Active Directory blade inside the Azure Portal and create a new `App registration`. I’ve called mine `ConsoleGraph` because I’m creating a console application to query my AAD.

overview of app registration

On the overview page, you can see both the `Directory (tenant) ID` and `Application (client) ID`. You’ll be needing these later on.

Next thing you need to do is to add a new secret to this application. It doesn’t matter much how you call this secret, just be sure to remember/copy the value as it’s very important and you won’t be seeing it again inside the Azure Portal.

application secret blade

Now that you have all of the details for this application, you still need to make sure this application has the appropriate permissions to query the Azure Active Directory.

Navigate to the `API permissions` blade. Over there, you should be able to add the permission to `Read directory data` from the AAD.

api permissions overview

Your application, `ConsoleGraph` in this sample, will now be able to read all data from the AAD. If you’re very keen on security, you might want to strip down the permissions a bit, but this is good enough for me.

How to connect my application to AAD

Making a connection to the AAD was the trickiest part for me. You have to create an `ActiveDirectoryClient` and create an `AuthenticationContext` which is able to acquire tokens from the AAD.

While this all works, you HAVE to know which settings to use on each specific property. Making a typo or messing up a setting will result in you not receiving a valid token and the error messages aren’t very useful (to me).

Put your application settings in a configuration file

The details of the `Application registration` should be put inside some configuration file, like an app.config file. In a production system, you might want to store the secret values in a more secure system, like Azure KeyVault. For this sample project the app.config is good enough.

Having added the details to your app.config file, your `appSettings` will probably look something like this.

<appSettings>
	<add key="TenantId" value="b1f9cb25-7c7a-4ecd-96c1-513c2b42c350"/>
	<add key="TenantName" value="myTentantName.onmicrosoft.com"/>
	<add key="ClientId" value="d82c0c6a-8c14-4c42-8aca-60c79fcfc9b4"/>
	<add key="ClientSecret" value="27?_MOh_qM633Hcccct;cw:@*$9ojcsNxve)rYI"/>
</appSettings>

I’ve created a small `Settings` class where all of these values are loaded in the appropriate format.

internal class Settings
{
    public const string ResourceUrl = "https://graph.windows.net";
    public static string TenantId => ConfigurationManager.AppSettings["TenantId"];
    public static string TenantName => ConfigurationManager.AppSettings["TenantName"];
    public static string ClientId => ConfigurationManager.AppSettings["ClientId"];
    public static string ClientSecret => ConfigurationManager.AppSettings["ClientSecret"];
    public static string AuthString => "https://login.microsoftonline.com/" + TenantName; 
}

Getting the right values for the `AuthString` and the `ResourceUrl` was the hardest part. The posts I found on the internet weren’t very helpful as each post used some other value and it wasn’t very clear to me what they are for. Eventually, I found these values to work for me.

Connect to AAD

Connecting to AAD is fairly straightforward.
As I mentioned, you need to create an `ActiveDirectoryClient` and use an `AuthenticationContext` in order to retrieve valid tokens.

I’ve used the following block of code to connect to Azure Active Directory and retrieve data from it.

public static ActiveDirectoryClient GetActiveDirectoryClientAsApplication()
{
    Uri servicePointUri = new Uri(Settings.ResourceUrl);
    Uri serviceRoot = new Uri(servicePointUri, Settings.TenantId);
    ActiveDirectoryClient activeDirectoryClient = new ActiveDirectoryClient(
        serviceRoot,
        async () => await AcquireTokenAsyncForApplication());
    return activeDirectoryClient;
}

private static async Task<string> AcquireTokenAsyncForApplication()
{
    AuthenticationContext authenticationContext = new AuthenticationContext(Settings.AuthString, false);

    ClientCredential clientCred = new ClientCredential(Settings.ClientId, Settings.ClientSecret);
    AuthenticationResult authenticationResult =
        await authenticationContext.AcquireTokenAsync(
            Settings.ResourceUrl,
            clientCred);
    string token = authenticationResult.AccessToken;
    return token;
}

How to retrieve data from AAD

By using the Active Directory helper method from the code block above you’re able to query everything inside your AAD.

The `ActiveDirectoryClient` can query all of AAD, including the users.
I’ve used it myself to iterate through all of the users and print them per line. You can also use the client to retrieve a specific user by querying on the `ObjectId`. This will result in retrieving a single user.

var client = AuthenticationHelper.GetActiveDirectoryClientAsApplication();

try
{
	var users = await client.Users.OrderBy(user => user.DisplayName).ExecuteAsync();
	var foundUser = await client.Users.Where(user => user.ObjectId == "d62d8c6a-dc69-46c1-99c4-36cd672f0c12").ExecuteAsync();
	foreach (var user in users.CurrentPage)
	{
		Console.WriteLine(user.DisplayName + " " + user.ObjectId);
	}
}
catch (Exception exception)
{
	Console.WriteLine(exception);

By using this `ActiveDirectoryClient`, you can now start to authorize users based on their details like for example a role, group or e-mail address.

If you’re interested in a ready-to-go sample, you can check out my GitHub repository containing all the details and a working console application.

I hope this post will help others because it has surely taken up too much of my time to find out what I needed to do exactly in order to retrieve user data from AAD.

comments powered by Disqus