Intro
Welcome to the second part of my tutorial about scopes in Azure Active Directory. During the first part, I described the basics about scopes e.g. how to get a token that contains specific scopes or how to add scopes into your application. You can find a link to it here.
In this part, I'll cover how to complete more advanced features or setup features that you don't normally configure on a daily basis. If you haven't looked at the first part of my tutorial, I highly recommend doing it because in this part I'll continue working on the applications that have already been created. In addition, I'll sometimes briefly mention procedures that are expanded upon in more detail in the first part. E.g. the first request required for getting a token means "sending GET request in your browser", and a second request means "sending POST request to exchange the authorization code for a token".
Let's begin once again from approving consent scopes.
Administrator only consent scopes - another way to approve
There is another way that an administrator can give consent to a scope. If the Global Administrator clicks the link below:
https://login.microsoftonline.com/{tenant_id}/adminconsent?client_id={client_id}
They'll be redirected to another consent view, and after giving consent, the status of the scope should change to green. Bear in mind that in place of {tenant_id}
in the above link you need to place your Tenant ID and similarly in place of {client_id}
, the Client ID of your ClientApp should be placed.
The outcome will be the same as clicking the button "Grant consent for …" as I presented in the "Scopes that only Administrators can consent to" section in the first part.
It's also possible to enable users to send a request to the administrator, requesting them to Grant permission using the build-in flow. In order to turn on this feature, you need to go to:
Your Azure Active Directory instance -> Enterprise applications -> User settings -> set "Users can request admin consent to apps they are unable to consent to" to Yes.
After the administrator who will receive requests to their email is selected, the window stating that administrator approval is required will change slightly, as can be seen below:
Manifest
There is another way to create scopes. If you go to:
Your Azure Active Directory instance -> App registration -> BooksCollectionApp -> Manifest
You'll see the following Manifest file, it's in JSON format and contains the whole configuration of your application. In this JSON there is an oauth2Permissions array, underlined below, which contains all scopes in your application. You can easily create scopes by just adding items to the array, it must be remembered, that every single scope needs to have a unique property id and you can use any kind of GUID generator to generate this id. Below it can be seen how the Books.Read scope is set out in the BooksCollectionApp manifest.
Authorized Client Applications
In the "Expose an API" view there is another feature, apart from Scopes definitions, that I'd like to cover here. This feature is called "Authorized Client Applications", which is found below the table of scopes:
To analyze this feature, let's create another scope in the BooksCollectionApp (bear in mind that this process is contained within the BooksCollectionApp, not in the ClientApp):
Now let's add in an authorized client application, you do this by clicking the "Add a client application" button in the "Expose an API" view. As can be seen below, you need to paste the ClientApp's Client ID into the Client ID input and then tick the box: Books.ReadWrite.
And click the "Add application" button.
Please note, you should wait a couple of minutes before trying to get the token. After waiting a few minutes, send the request to obtain an Authorization Code in your browser, be sure to use the Books.ReadWrite scope and the ClientApp's Client ID and Client Secret. It can be seen that the consent window didn't show up at all, even though this action was performed for the first time. While not being apparently obvious, you were redirected to the localhost and provided with an Authorization Code immediately. This is the main idea of this feature. As long as you trust the BooksCollectionApp, and the BooksCollectionApp trusts the ClientApp (by adding it to the Authorized client applications), thus, there was no need to show you the consent view. It was made in a more granular way, meaning enabling specific scopes for the ClientApp but not all of them.
I have discovered the following: when you add any scope in the "Authorized client applications" section, then you can't get a scope that requires administrator consent for a user. To display this, leave "Authorized client applications" with the Books.ReadWrite scope ticked, and try to get a token which specifies the Books.Read.All scope in the request. You should receive an error message which states that you need to be provided with admin consent. Once you remove the scope Books.ReadWrite from the "Authorized client applications", you'll once again be able to get the token.
Disabling the option that allows users to consent
If you'd like to disable the future user from being able to give consent in your organization. You can read Microsoft's recommendations here.
To carry out the above, go to:
Your Azure Active Directory instance -> Enterprise applications -> User settings -> set "Users can consent to apps accessing company data on their behalf" to No.
As below:
To see this feature in action, one additional scope in the BooksCollectionApp should be added:
Fill in the inputs like above and click the "Add scope" button. Let's try to get a new token, using the new scope, firstly compose the Authorization Code request and copy this from the Postman to your browser:
After sending the request, the consent window should look like below:
Now you can see, despite the fact that the scope is set for admins and users, only a Global Administrator can give consent to the ClientApp. Since a regular user can't, the only way to allow regular users to get a token containing the specific scope is to add the application and scope to the "Authorized client applications" as found in the "Authorized Client Applications" section. This option gives the owner of the BooksCollectionApp control over which applications can have access to which scopes.
Note that we have seen this feature in action, to continue this tutorial switch "Users can consent to apps accessing company data on their behalf" back to "Yes". Please note, it can take a while to make this particular option work properly, in my case it took about 10min.
Prompt Query Parameter
After you give consent to a scope, the consent window won't pop up again, asking you to give your consent, a second time for the same scope. To force AAD to show a user the consent window every single time, you have to add one additional query parameter into the first request, the parameter's name is prompt. Go ahead and send the same request from your browser as in the example provided at the beginning of the first part tutorial with the modification that is shown below. Another important consideration, is that you shouldn't have any Authorized client application scopes in the BooksCollectionApp.
As you may have probably noticed, every single time you send the request you receive the consent window, even though you have consented already earlier.
There are a few different options for the prompt parameter, these include, e.g.: login, none and select_account. You can read about them here.
Display names
While creating scopes, you should know that you need to provide display names and descriptions for the scope (actually, only the display name and description for administrators are required). The display name and description for users are displayed on the regular consent window. The administrator’s display name and description will only show up when the administrator grants consent for the client's app using the following link:
https://login.microsoftonline.com/{tenant_id}/adminconsent?client_id={client_id}
If you'd like more information on the granting consent by following a link process, you'll find it in the section "Administrator only consent scopes - another way to approve".
Scopes in Authorization Endpoint V1 and V2
In the "API permission" view we didn't have to add any scopes to our client's application that didn't require administrator consent, because we used Azure AD V2 Authorization Endpoint, instead we specified them in the request's query parameters (dynamic consent). If we had used V1, we would have had to specify all scopes in the "Api permission" view (static consent) instead of in the request's query parameter, this is because in V1 there is a resource query parameter (where you add Application URI or Client ID), not the scope query parameter. You can find more information by clicking the following link.
Client Credentials flow
In the Client Credentials flow, in comparison to the Authorization Code flow, a user can't be present, therefore, this flow is popular in the case of service to service connections (e.g. One Azure Function sends a request to a different Azure Function). In order to obtain an access token, only one request is required. On the screen below, you can find the details of the request:
As you may have probably noticed, this request is similar to the JWT exchange request, not only is it a POST request, it also has the /token endpoint. The two main differences are shown above, in the grant_type
parameter Client Credentials flow can be easily seen. What about Scopes? I'll give a detailed explanation below.
In case of the Client Credentials flow scopes aren't possible, this is because it is not feasible for a user to be able to give consent, this is especially because, as was mentioned before, there is no user in this flow. It must be mentioned, however, that a scope parameter is required in a request, so in order to comply with this rule, the value of the scope parameter should be either {{Application ID URI}}/.default
or {{Resource application ClientID}}/.default
.
If you decide to send the above request and decode the access token using e.g. https://jwt.ms, you'll discover that there is actually no "scp" claim at all, because it's not relevant in this scenario.
In the next article I'll explain Roles in the Azure Active Directory, these will be able to be assigned to both applications and users, that being said, they can be visible in the JWT for both cases.
More than one scope
There is a possibility to specify more than one scope, in the scope parameter in the request you can add another scope by inserting a space between them. If you look closely you can see this below:
The space is the separator between scopes, however, they must be from the same application e.g. https://bookscollectionapp.com
. You'll receive an error message if you specify more than one scope from different applications:
Client ID instead of Application ID URI
Whenever you send a scope in the request, there is another way to specify the resource application. Up until now, we have always used {{Application ID URI}}/{{scope}}
pattern, but instead of providing the Application ID URI we can just use {{Resource application ClientID}}/{{scope}}
. So in our case, the first request should look like below:
Bear in mind that in your case, the value of the BooksCollectionApp Client ID must equal your BooksCollectionApp Client ID. Using this approach has one consequence that comes to my mind. If you exchange the Authorization Code for the JWT, and decode it (I've shown how to obtain it in the first part of the tutorial), it should be apparent, that instead of the Application ID URI in the "aud" claim, you'll see your Resource Client ID in your token. Below you can find the specific fragment of my access token:
Summary
We've now finished the second part of my scope tutorial. In the next coming weeks, I'm going to release a similar tutorial to this one which will cover Roles in Azure Active Directory. I hope that scopes are now more familiar to you than at the beginning of the tutorial. If you have any further questions feel free to write some comments below.
Top comments (2)
Cover Photo by Bradley Dunn on Unsplash.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.