Configuring Roles in Azure Active Directory
Tags: azure, oauth, roles, aad
Published: 2020-10-15 04:53:00

## **Intro**
In my previous articles I've uncovered how to configure scopes in Azure Active Directory (If you haven't seen them, you can find the first part [here](https://dev.to/czmiel24/configuring-scopes-in-azure-active-directory-part-1-3bio) and the second part [here](https://dev.to/czmiel24/configuring-scopes-in-azure-active-directory-part-2-3npp)). In this tutorial, we'll work on roles, which is a great mechanism, used for authorization. Firstly I'll explain the basics of the RBAC concept, and then by using an example, I'll walk through the main features related to roles in AAD. So let's get started.

## **Concept**
In the concept of scopes, the user **allows** the client's application to perform particular actions on behalf of them in a resource application. The RBAC (Roles Based Access Control) concept states what a user/application is **allowed** to do in a resource application, based on the particular roles they have. It means that, for example, the user that has the role of *Reader* can read books, but they can't moderate them because they don't have the role of *Moderator*. This means it's more focused on what the end-user/application can and cannot do. This is a really rough definition, thus, I encourage you to read some articles on the internet about it if you don't feel confident about RBAC. There are plenty of articles but [this](https://auth0.com/docs/authorization/concepts/rbac) is one I can highly recommend.

## **Creating applications**
First of all, we're going to need to create two applications in AAD(the same as in my Scopes tutorial): both a Client and a Resource application. You can do this by following these steps:

*Your Azure Active Directory instance -> App registration -> New registration:*

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/xvt238i13dhhlw8z3xoi.png)

You need to fill in the Name textbox (you can provide a different name, of course, but I suggest using the same one, because I’ll continue to use the same name throughout this tutorial):

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/j0pzwzds6bqg58g6h8sc.png)

The same requirement needs to be completed for the Resource Application. As shown in the screenshot below:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/rc5zznwuvfg3vq0vgxr7.png)

We’ve created two different applications in AAD (these are not WebService or Azure Function applications or any other — both are only representations of physical applications in AAD):

* **ClientApp** — this application represents the service that communicates with the Resource application directly, for example, service to service (e.g. an Azure Function communicates with another Azure Function). This is why we'll use this application when assigning roles to the application, and acquiring token using Client Credentials. For flow where a user is present I'll use OpenID Connect in which using the *ClientApp* isn't needed, but won't feel afraid, I'll present the example step by step. If you aren't familiar with OpenID Connect, in my first tutorial about scopes I've attached great video about it, so feel free to watch it.
* **BooksCollectionApp** — this application represents the Resource Application that may have sensitive information belonging to the User (e.g. WEB API could contain a User’s secret books).


We need to set up a few things before we go on to creating roles. Firstly, we have to add a redirect URL to both our applications. Second, we have to enable ID tokens for the BooksCollectionApp, as we want to use OpenID Connect to authenticate users.

Let's go to the Authentication option in the *ClientApp* by following:

*Your Azure Active Directory instance -> App registration -> ClientApp -> Authentication*

Click the "Add a platform" button, and on the panel on the right hand side, select "Web block":

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/c91cvq29v3gqf8aex7r6.png)

Next, fill in the Redirect URLs as shown in the screen below:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/hqutcoz7bvrk2xesclls.png)

Then click the "Configure" button. You may notice that I've put the localhost there. This is because it's for testing purposes, and I don't want to be redirected (my code being sent) to other websites. In the real case scenario, you should provide the address to your real hosted application.

We almost have to replicate the same actions for the *BooksCollectionApp*, however, the ID tokens checkbox must also be selected, as shown:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ymjpotwoh811e7hhmr4q.png)

Again click the "Configure" button.
Now the prerequsites have been completed, we can start to focus on, the main point of this tutorial, roles in our applications.

## **Creating roles**


In the Azure Active Directory we can differentiate two types of roles: one for users, and another for applications. While this tutorial was being created, the only way to define roles in an application was to do it in the application's Manifest (application definition in JSON format). Let's go ahead and create one for a user and one for an application.

To get to the Manifest, you have to follow:

*Your Azure Active Directory instance -> App registration -> BooksCollectionApp -> Manifest*

Once completed, you should see a similar screen, as below:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/oqygecsv9b4tml6164yd.png)

The red underlined part shows the definitions of the roles, this means there haven't been any roles defined in our application yet. Let's create one by adding an item into the array, as shown in the snippet below:

```
    {
        "allowedMemberTypes": [
            "User"
        ],
        "description": "Enables a user to read books",
        "displayName": "Reader",
        "id": "2ef66a29-eaa8-4b0d-8763-aaafb2002a5a",
        "isEnabled": true,
        "lang": null,
        "origin": "Application",
        "value": "Reader"
    }
```

We've created a *Reader* role that only exists for users (because we've inserted a `User` value into the `allowedMemberTypes` array). In the final application (e.g. WebAPI or Azure Function) this role can be used to permit all users that have the *Reader* role to read books. 
Next, we'll create another role, this time for applications only:

```
    {
        "allowedMemberTypes": [
            "Application"
        ],
        "description": "Enables an application to create/edit/delete books",
        "displayName": "Moderator",
        "id": "67d25112-7487-4cce-a131-d933adb7ff95",
        "isEnabled": true,
        "lang": null,
        "origin": "Application",
        "value": "Moderator"
    }
```

In the snippet above, we've created the role *Moderator* which can only be used by applications (the value `Application` can be seen in the `allowedMemberTypes`). This could mean that, only applications that contain a token with the role of *Moderator*, can moderate books in the end application. 
After our changes, the *appRoles* part of the Manifest file in the Portal should look like this:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/wqzv6rxub7mx7ydm5wdq.png)

Keep in mind that, when you create a new role, you have to provide a unique `id` every time. I encourage you to use a GUID generator for this purpose. The second thing that I'd like to point out is, you can create a role that can be assigned to both users and applications. You can do this by adding two items to the array.

## **Assigning user roles**

In order to assign a role to a user, you first have to go to:

*Your Azure Active Directory instance -> Enterprise applications-> BooksCollectionApp -> Users and groups*

Then, click the button "Add user" as shown in the screen below:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/t65i6v2uai1vearbfj0p.png)

In the next screen, you can specify what role should be assigned to the user. For the non-testing solutions, I wouldn't recommend assigning a role to single users, hovever, I would instead assign a role to the whole group as it ensures less maintenance work in the future. For this tutorial though, we'll only assign a simple role to the user, namely the `Reader` role.

In the "Add Assignment" view select the user that you want to assign the `Reader` role to, and as far as the role is concerned, you don't need to select anything because we've only specified this one specific role for the users purposes. The assignment should resemble the screen below:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/dgvtntw6ogq6h1be5wdc.png)

After clicking the "Assign" button, you should be redirected to the "Users and groups" view, which shows the assignment that we've made:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/1gzm0iiwn0r7yuf6mdxd.png)

Perfect, so now we can check if the `Reader` role is visible in the user's token. In my previous tutorial, I've shown you how to get a token via Authorization Code and Client Credential flow, but now we'll take advantage of Open ID Connect to get a token for the user. 
Let's prepare the request in the Postman, as shown below:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/vrywfp4lnahbjdtxdrs2.png)

Remember that in place of the black box (between domain name and `ouath2` element in the URL) you have to place **your** tenant id and in place of the `client_id` value, you must insert the Client ID of **your** BooksCollectionApp. The parameters `response_type` and `scope` show that we want to obtain a token using Open ID Connect. The `redirect_uri` that was provided at the start of this tutorial must be inserted in the same way during the creation of the application. The `nonce` parameter is there for security reasons, to prevent token [replay attacks](https://medium.com/@benjamin.botto/oauth-replay-attack-mitigation-18655a62fe53) (it should be a random value, but in our case I've chosen a pretty round one).
Copy the request's URL and paste it to the browser, then you'll be redirected to the login page. 
Remember that you have to log in as the user that you've specified in the role assignment view. After logging in, you should be able to see the consent view:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/dvdm6ky82ljskecaa5th.png)


If you give the application consent, you'll be redirected to a localhost and in the query parameters you'll be able to see the token, as shown in bold below:

<code>https://localhost:44327/signin-oidc#id_token={<b>TOKEN</b>}&session_state=7d973d4b-3c74-49be-c180abf</code>

Copy the token, and paste it into the input box, from this page: https://jwt.ms which will allow us to decode the token and to see what's inside. After doing that you should be able to see a view, similar to this one:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/3lkiax2f41w53mqpsjwr.png)

You can see, that our token has two very important claims: `aud` which points to the *BooksCollectionApp*, and `roles` which states what roles have been assigned to us. Based on this information, the end application e.g. Azure Function or WebAPI is able to authorize the action that we want to perform. In our case, it means that we're able to read books.

Try getting a token for other users that haven't been assigned to this role, and check to see if they also have the same `Reader` role in their token!

In this tutorial, we've used OpenID Connect to get the token, hovever, it should be noted, that you can also use Authorization Code flow, just as we've used in the previous tutorials. You can treat this as homework ;)

## **Assigning application roles**

In this scenario, we would like to assign the role of *Moderator* to the *ClientApp*. This can be extremely helpful when, there are for example, many services that connect to one service and we only want to allow certain services to perform particular actions, in this case, role based access control fits well. To configure it in AAD, first of all, you have to go to the "API Permissions" view in your *ClientApp*:

*Your Azure Active Directory instance -> App registration -> ClientApp -> API Permissions*

Firstly, click the "Add a permission" button, subsequently the panel on the right-hand side should be displayed. The "My APIs" button must be selected and the "BooksCollectionApp" clicked, as shown in the screen below:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/rniwy7u353jg356x1xh5.png)

The panel should change to the one presented below. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/ujbyhxtdj6j6t4na5qmg.png)

On the panel, you can see two types of permissions: Delegated and Application. In the previous articles about scopes, I've explained that "Delegated permissions" are related to scopes. Application permissions though are related to the different roles that can be assigned to applications. This means that if you click "Application permissions", you'll get a list which shows all the roles from the selected application that are defined by "Application" in the `allowedMemberTypes` contained within Manifest. This is why you can only see the *Moderator* role, without the *Reader* role. 

Let's select Application permissions, check *Moderator* role, and click the "Add permissions" button. 

After that you should see the list of scopes and roles, as presented below, that have been assigned to the *ClientApp* application:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/76c8cdld00sqzshpqtq3.png)

You can see that the *ClientApp* application has two permissions assigned:
* User.Read - which is a scope (this is because the type column is "Delegated").
* Moderator - the role that we've just assigned.

All application roles require "Admin consent", this means that the Global Administrator has to click the button "Grant admin consent for..." to make these roles work with the application. Go ahead and click the button "Grant admin consent for..." which can be seen above in the permissions table. After clicking it, you should see that the status of the permission has changed to allow access, as can be seen with the green tick. A similar view is shown below:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/mhh0idfgfm3twxru2jgk.png)

The last step to ensure you have the "Moderator" role is to get a token to check if the "Moderator" role is contained. We'll use the Client Credentials flow, because this is an OAuth flow that doesn't require a user. So let's generate a request in the Postman:

Keep in mind that the `client_id` and the `client_secret` are the Client ID and the Client Secret of your *ClientApp*. The `grant_type` parameter specifies that we're using the Client Credentials flow, and the `scope` parameter should be either `{{Application ID URI}}/.default` or `{{Resource application ClientID}}/.default` (I've described it better in my previous tutorial). In your case you should provide `{{Your BooksCollectionApp ClientID}}/.default`. As can be seen below:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/69ss3kjud9yndmijtlgr.png)

Send the request, copy the token and paste it to the following: https://jwt.ms. If you've done everything correctly, the *Moderator* role should be visible in your JWT. The token that has been obtained in jwt.ms looks like this:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/e80e8v6lan2rmiw8asdg.png)

If the role in the token contains *Moderator*, then you have correctly assigned it to the *ClientApp*. Additionaly, you can create another application in AAD and try to obtain a token for it, to ensure that there is no *Moderator* role included.

## **Summary**
We've now finished my basic tutorial on how to configure roles in Azure Active Directory. I hope that I have enlightened you on the Roles concept in AAD and it is now more familiar to you. If you want more information I advice you to check out Microsoft's documentation to get more details. If you have any further questions, feel free to write some comments below.