Microsoft Active Directory (AD) is a directory service for Windows domain networks, such as the domain network in an organization. When developing applications we often come across the need for integrating with Microsoft Active Directory, such as authenticating users within an organization and performing certain operations within the domain of the organization. In this post we’ll have a look at how to set up an application in AD by integrating with Microsoft’s cloud platform «Azure», how we can delegate user permissions through user groups in AD, and finally authenticating and authorizing users programmatically in .NET Core.
Before we get started, we should clarify some of the concepts we discuss in this post. First, let us have a look at the terms «authentication» and «authorization», which is not always easy to differentiate between. Shortly spoken, authentication is the process of confirming the identification of an entity – whether it is a machine or a human, whereas authorization is the process of determining what resources this entity has access to. For instance, there are millions of authenticated users on Facebook, but they are only authorized to edit their own profiles, not others’. We will now take a closer look at how we can set up an application in the Azure Active Directory, assigning a group of users that are allowed to access the application, authenticating these users programmatically in .NET Core with the OpenId Connect 1.0 specification, and finally authorizing users by following the OAuth 2.0 specification.
1 Go to the Azure Active Directory page
2 The Azure Active Directory dashboard should be displayed
3 Click on the «App registrations» -> «New application registration»
4 Enter the details of your app and click «Create»
The URL is only necessary for redirect-purposes, if the AD authentication should be integrated on the client-side and not the server-side
5 Search for the app you just created, and click on it
6 The dashboard of your app should look something like this
Save the value in the «Application ID» field, we will need this when we want to communicate with Azure Active Directory through our code later.
7 Click on «All settings» -> «Required permissions» -> «Add» to add permitted APIs for the app
Choose the APIs on the picture.
8 Click on the «Windows Azure Active Directory» API, select the following permissions and click «Save»
9 Click on the «Grant permissions» button. This requires a user with the Administrator role
10 Click on the «Keys» menu item and add key(s) that will enable clients to access the application
Remember to save the keys after you create them, as they will disappear forever after you leave the page. We will later on use one of these keys as our client secret when authenticating users programmatically.
11 Click on the application name link below the text «Managed application in local directory»
12 Click on «Properties» and make sure the two following options are set to «Yes»
13 Navigate to the «Users and groups» page in Azure
14 The «Users and groups» dashboard should look something like this
15 Click on «All groups» -> «New group»
16 Enter details for the group
17 Search for the group you just created and click on it
18 Click on «Members» -> «Add members» and add the users that should have access to the application
19 Navigate back to the «Azure Active Directory» page
20 Click on «Enterprise applications»
21 Click «All applications» and search for the application. Click on it
22 Click on «Users and groups» and «Add user»
23 Search for the user group, check its checkbox and click the blue button «Select»
24 When the group has been selected, click the «Assign» button
25 Make sure the user group are now visible in the «Users and groups» list
26 (Optional) Navigate back to «Users and groups» section, enter the group and click on «Applications» and see that the application now is assigned to the user group
27 Go back to the «Azure Active Directory» page
28 Click the «Properties» menu item, and copy and save the GUID value in the «Directory ID» field
This GUID is the tenant ID, namely the ID that we will later used for specifying the organization we want to authenticate users for.
29 (Optional) Go to «Application registrations» -> «Endpoints» link. These are the different endpoints you can interact with
The last fragment of the URLs (erased for security-purposes in this picture), typically a GUID, is your organizations tenant ID, and this will be used later on when we authenticate users in our code. Example: https://login.microsoftonline.com/ec866b05-929c-43d2-b65b-205e1976303d where the last URL fragment «ec866b05-929c-43d2-b65b-205e1976303d» is the tenant ID.
30 Programatically authenticating users through .NET Core
Now that we have set up an application in Azure Active Directory that only users in our assigned user group can log in to, we can now write some code to enable our users to authenticate themselves. Before we can do this we need the following values ready to inject into our code:
- tenantId: The ID/GUID of the organization (see step 28 for where to find this)
- authorityBaseUrl: The URL to the Microsoft login endpoint (https://login.microsoftonline.com)
- resourceBaseUrl: The URL of the Microsoft Graph API (https://graph.windows.net)
- clientId: The application ID (a GUID) that we saved in step 6. You can find this again by going to your app dashboard in the Azure Active Directory.
- clientSecret: One of the keys that we specified in step 10. This acts as the password when we communicate with Azure Active Directory.
With these values in hand we can use the following code to authenticate users programmatically:
31 Extract the access_token from the HTTP response
The response from the AuthenticateUser method in the previous step should look like this:
The authenticated user can now add an HTTP Authorization-header with the «Bearer» schema and the token from the «access_token» property from the HTTP response like this example: Authorization: Bearer eyJ0eXAiOiJKVIUzI1NiJ9.eyJuYW1lIjoibWFnbnVW1haWwiOiJtYWdudXMuc3R1aHJAaGF.sInJvbGxlIjowfSx7Imt1bmRlSWQiOjU . If we have a front-end client (web-page, mobile app GUI etc.), which most applications do, then of course the client-code should add the Authorization header with the Bearer schema without the users knowing at all. The users should just type in their username and password, and then have access to the authorized information in the front-end client.
The «Bearer» schema with the JSON Web Token (JWT) will be the way the user (usually through the front-end client) can authorize itself when using our APIs, but before this can happen we need to set up an automatic authorization of the tokens that are provided by the Open ID Connect provider (in this case Microsoft).
32 Set up authorization for your Active Directory app
Make sure the following packages are included in your project:
Now we can create an extension class that will let us configure JWT Bearer authentication that will automatically authorize the tokens provided in any request with the «Bearer» schema that looks like this (we will later call this method in our Startup class for our API):
Here we add the public keys from the Open ID Connect provider to verify the signature of the incoming tokens to our API. The JWTs are signed with the RSA algorithm, meaning that the provided public keys of the Open ID Connect provider can only verify JWTs that are signed with secret private key that only the issuer are in possession of. This way, if the signature verification succeeds we know that the JWT is signed with the correct private key, and has not been tampered with.
Finally, in the Configure-method in our Startup class for our API we can call this extension method:
Now we can add the Authorize Attribute for any Controller method we have, and it will automatically validate the signature and expiration of the JWT sent in the «Authorization» header with the «Bearer» schema. This will authorize any valid JWT token from the tenant ID, meaning that any authenticated user in the tenant/organization can access the APIs. If we however want to only let users with permission to a given application be authorized, then we can add a customized authorization policy in the ConfigureServices method of our Startup class like this:
The «myAppUser» is the name of our authorization policy (can be named anything you want), whereas the «appid» claim type is the name of the claim containing our application ID in the access-token we got back from the login-endpoint when authenticating the users.
The last step is to now add an Authorize attribute for all our HTTP methods in our controllers that should only be permitted to users that have logged in to our Azure Active Directory application. Here we refer to the policy name from the previous code snippet («myAppUser»):
Now we have a fully implemented stack of setting up an application i Azure Active Directory, assigning user group of permitted users for the application, and authenticating and authorizing users through our own APIs.