MSAL Authorization Url shows already consented scopes again - azure

I registered an application in my Azure tenant A. This application can work as multitenant application.
Then, I created another tenant B. Then, as an admin of the tenant B, I wanted to give consent for User.Read.All to that application by using below url:
https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize?scope=openid+profile+offline_access+User.Read.All&response_type=code&redirect_uri=https....
Above url opened a permission required pop-up which is like below:
Then as an admin of tenant B, I gave consent for that two permission.
Also, when I enter to tenant B account, I can see the application and my consented scopes which is User.Read.All and Maintain access to data you have given it access to.
Later, I want to give another consent which is Directory.AccessAsUser.All to that application.
so I use the below url to getting permission.
https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize?scope=openid+profile+offline_access+User.Read.All+Directory.AccessAsUser.All&response_type=code&redirect_uri=https....
However this above url show me again the descriptions about the User.Read.All and Maintain access to data you have given it access to although I have already given consent for them previously. I expected to see only the Access the directory as you which is description of Directory.AccessAsUser.All.
Does Microsoft has a solution for this? Or should I manage scopes manually by storing consented them so I don't use them again in the url? Also I still not sure that second manual option solve the repeatedly showing Maintain access to data you have given it access to problem for every incremental consent.

I follow the steps as yours and reproduced it when calling with scope=openid+profile+offline_access+User.Read.All+Directory.AccessAsUser.All.
It seems that if calling the /authorize endpoint it will show the permissions of scope. So I tried to add Chat.Create for test.
When calling with only scope=Chat.Create:
When calling with scope=openid+profile+offline_access+User.Read.All+Directory.AccessAsUser.All+ Chat.Create:
But unfortunately, I don't find the official document about Permissions requested.
Note: offline_access is used for refresh_token.

Related

Register app in Azure AD to access CDS Web API

I'm trying to figure out how to integrate an external app with Microsoft CDS Web API. The first step would be to try the Wep API with Postman. Following this document I could authenticate and make requests to the API using the client id provided in the document. However, when I try to register my own app in my AAD, I can't get the access token in Postman without having first to request the admin for consent.
I followed the instructions in this document to register the app, plus I allowed implicit flow. A did this in a trial account, where I'm the admin and then I tried retrieving the token with an user of another tenant (where I'm not an admin) it tells me to ask the tenant for consent.
Do you know how to register the app without non-admin users having to request admin consent?
Edit:
The registrated app has the following permissions, where none of them require admin consent:
Screenshot of the selected permission
The tenant which the non admin-users belong to has the following configuration for users being able to consent access:
Screenshot of user settings
Anyway, I assume these last settings would not be the problem because when requesting the token with the client id provided by Microsoft in the example of the first link, I do not require the consent from the admin.
Just for the sake of clarity, this is the step that I would like to remove from the authorization process:
Screenshot of the consent request screen
First of all you need to know that not all permissions require admin consent.
Dynamics CRM user_impersonation permission doesn't require admin consent.
But you need to make sure all the permissions added into your registered app don't require admin consent. As long as any permission requires admin consent, then admin consent cannot be bypassed.
Besides, make sure this configuration has been abled in the tenant(which the non-admin users are from).
UPDATE:
You are correct. After testing, I found that this permission does require admin consent. I believe this is an error in the documentation. It seems that the conclusion is that we cannot bypass admin consent.

Is Azure's User.Read permission required for OAuth consent forms?

My multi-tenant Azure application requires only the app-level EWS legacy permission full_access_as_app to run. This app-level permission can only be consented to by an administrator---it's extremely powerful because it gives the app read and write permissions over every EWS mailbox in a tenancy.
If I, as an admin for my Azure tenancy, grant my application only this single permission behind the scenes in AAD configuration, everything works fine when I run the application for my tenancy.
However when you create a new app in Azure, Azure always assumes you will want the user-level Graph API User.Read permission automatically. When you try to remove the permission you get this ominous warning:
And in the case when I leave it out, interactive OAuth consent forms don't work. The error message looks like this.
The client has not listed any permissions for 'AAD Graph' in the requested permissions in the client's application registration. Or, The admin has not consented in the tenant. Or, Check the application identifier in the request to ensure it matches the configured client application identifier. Please contact your admin to fix the configuration or consent on behalf of the tenant.
In other words, it appears that the application won't be able to run for anyone else's tenancy because their admins can't consent to it.
My hypothesis is that this is because Azure is using the User.Read permission to check whether the person signing in through the OAuth form is an administrator. In other words this permission is needed just this one time, before the application is ever run for the admin's tenancy.
Looking at the actual OAuth consent form, this does appear to be the case.The app wants to sign in and read my profile, to check if I am admin... or so it seems to me.
Am I right about this? Documentation I have been able to find is rather scanty.

Azure Active Directory needs Admin Approval after setting prompt =consent

In my application in Azure Active Directory I have added one of the Admin's consent required permission to the Graph API, let say Group.Read.All. I've clicked Grant Admin Consent for .... If I hit /authorize endpoint as a User with the query parameter prompt=consent, I'll get the view that I need admin approval. If I hit the endpoint without any prompt parameter, everything works fine - I'm able to get a token with a proper scope. In the documentation I've read that prompt parameter determines only the visibility of the consent. Why it works like that?
Regarding prompt=consent, OpenID Connect says:
The Authorization Server SHOULD prompt the End-User for consent before returning information to the Client. If it cannot obtain consent, it MUST return an error, typically consent_required.
In the Microsoft Identity platform, this means that the end user will be required to provide consent, even if consent has been granted previously by the user or (in the case of work or school accounts, by an administrator on behalf of the user).
If the user is not authorized to consent to the requested permissions (e.g. because user consent is disabled or restricted), using prompt=consent will always result in a hard block for the user.
In most cases, using prompt=consent is not the best approach. There are typically three scenarios prompt=consent is considered:
You've changed the required permissions. The required permissions have changed (e.g. permissions have been added or removed), and the user needs to consent to the new set of permissions.
You want to inform the user. The app developer wishes to ensure the user is informed of which permissions the app will be authorized to exercise (even if an administrator has already consented on behalf of the user in question).
You require consent from the user themselves, not an admin. The app developer wishes to ensure the end-user themselves provides consent, independent of what an administrator may have authorized previously.
If you've changed which permissions are required
When the requested permissions are defined dynamically
On the v2.0 endpoint, the scope parameter can be used to dynamically request a list of delegated permissions. For example, to request the read and export delegated permissions of the API identified by https://api.example.com:
scope=openid https://api.example.com/read
Azure AD will ensure that all the requested permissions have been granted, and attempt to prompt for consent for any permissions which have not yet been granted (and only for those). If the requested permissions have all been granted, the issued token will include all granted permissions (even if they were not specifically requested).
Generally speaking, when making use of the incremental consent capability of the v2.0 endpoint, prompt=consent should not be used. Azure AD will take care of prompting for incremental consent if needed.
When the requested permissions are defined statically
An app can also identify only the resource (i.e. the API) for which it is requesting an access token, the specific permissions being defined statically for the app. Using the v2.0 endpoint, this is done in the scope parameter, making use of the special .default permission value:
scope=openid https://api.example.com/.default
In the v1.0 endpoint, this was achieved using the resource parameter:
resource=https://api.example.com
The list of required permissions is configured in a static list on the app registration. In the Azure portal, this list is under Configured permissions in Azure AD > App registrations > API permissions. In the unerlying Application entity in Microsoft Graph (and in the app manifest), this is stoerd in the requiredResourceAccess property.
On receiving a request of this type (on either the v1 or v2 endpoint), Azure AD will check which permissions have been granted for the requested resource:
If no delegated permissions have been granted for the requested resource OR if prompt=consent is used, Azure AD will attempt to prompt for all the required permissions from the statically-defined list. This will include permissions for other APIs, if any are configured.
If any delegated permission has been granted for the requested resource, Azure AD will issue the token with all granted permissions. The scopes parameter of the response will include the list of permissions included in the access token.
Applications relying on statically-defined required permissions (i.e. /.default on v2 or resource on v1) should not use prompt=consent for every sign-in request. Instead, the application should:
Perform a sign in without prompt=consent.
Check the scope parameter of the response:
If the desired permissions are listed, no further action is necessary.
If not (e.g. if a new permission was added to the list of required permissions after the user initially consented to the app), only then should the user be sent back again, this time with prompt=consent.
This strategy ensures that users can sign in to an app when an administrator has consented on their behalf (e.g. because they aren't authorized to consent on their own), and only forces the consent prompt (or an escalation to an admin to consent on their behalf) when a new permission has been configured.
If you want to inform the user
Using prompt=consent is not a good approach if the goal is to only inform the user of which permissions the application has been authorized to exercise (either by the user previously, or by an administrator on the user's behalf).
Instead, an application can use the scope parameter of the token response to construct the desired interrupt experience (e.g. after the user has been redirected back to the app and the token has been retrieved, but before continuing), informing the user of which permissions it has been granted.
If you require consent by the user, not an admin
There may exist very specific cases when an application requires user consent for the requested permissions, and wishes to not accept consent granted on behalf of the user by an administrator.
In this case, using prompt=consent in all sign-ins could be used, but there are important caveats to consider:
In many organizations, user consent is disabled or restricted. If users are not authorized to consent to the permissions configured for your app, they will not be able to use your application.
The user will be prompted for consent every single sign-in, even if the user themselves already previously granted consent.
Since this is a query parameter, a knowledgeable user could very easily intercept the request before it is made, and remove prompt=consent (and if consent was already previously granted, they will not be prompted for consent).
In this case, it may be better the app to implement a separate consent-granting experience after the user has signed in (similar to the "inform" scenario described earlier), separating the app's additional consent requirements from the consent experience provided by the Microsoft identity platform.
prompt=consent triggers the OAuth consent dialog after the user signs in, asking the user to grant permissions to the app.
Individuals accessing an app that requires at least one permission that is outside their scope of authority.
Admins will see the same prompt show the permission and will see an additional control on the traditional consent prompt that will allow them consent on behalf of the entire tenant.
Users will be blocked from granting consent to the application, and they will be told to ask their admin for access to the app.
For more details, you could refer to this article.

Azure AD + Graph API: How to reconsent after new permissions?

I have an application registration in Azure AD which has some Graph API delegated permissions set for it.
The application is simply a page in SharePoint that is making the Graph calls, authenticating with the ADAL.js library.
I now want to make an additional Graph call on the page to a new Graph API endpoint so I need to assign the application an additional permission. I set this permission in Azure AD and save. However, the user accessing the SharePoint page is never asked to reconsent to the new permissions, therefore the new Graph call fails with a 401 Unauthorised message.
I have tried this with a number of different endpoints and permissions, and I am sure I am setting the correct permissions in the application.
How can I have the consent dialog appear for users automatically when the application permissions change?
Admin consent is not an option.
I remember having a discussion about this with a member of Azure AD team some time back and this is what he had suggested at that time (though I never tried it so it may not work).
Essentially what he suggested is that when you get Unauthorized (401) error, you redirect the user to Azure AD login again i.e. follow OAuth authorization flow again but include prompt=consent in the sign in URI. This will present the user a consent page with latest permissions. Once the user consents to the latest permission, you can redirect the user back to your application. You may find this link helpful for understanding different values for propmpt parameter: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-openid-connect-code.
Again, I have not tried this personally so it may not work. If it doesn't, please let me know and I will remove my answer.

How do I add users to tenant via the Graph API?

I've utilized the Partner Center REST API to provision tenants with orders/subscriptions. Now I want to start configuring the domains and users for the tenant I just created. My first step was to get a list of users using the Graph API https://msdn.microsoft.com/en-us/library/azure/ad/graph/api/users-operations as a test expecting to see the admin account. If I pass in the domain of the reseller account in the request URL, it shows me the reseller users. But when I put in the domain of the account I just provisioned, I get Invalid domain name in the request url. I'm using the resellers AD token to do this. I'm confused as it gives me the option to specify a domain, but I can only access my own.
What credentials am I supposed to be using here? I tried to use the user/pass that was generated for the admin account from the provision, but I get unauthorized_client when trying to get an AD token from the Graph API.
It is hard to directly address your issues here since they are a little broad, and I would need more specific details about the various tenants you are working with, how your app is provisioned, permissions your app has etc...
However I think there a few principals you can follow which may help you debug your issues.
All AAD Authentication happens within the context of a specific tenant. This means whenever you get an access token for a resource, the scope of that token is limited to the boundaries of the tenant.
To authenticate with a client application in the context of a tenant, you must have the app registered in the tenant you are trying to access (line of business application / single tenant) or you have to make the app multi-tenant, in which case your app should be able to function in the context of any tenant... if the right provisioning has occurred.
Every tenant where your app is trying to function must have a service principal for the application provisioned in the tenant. This service principal represents your application's identity in the context of that tenant, and acts as a place to store the permission your application has in the context of that tenant. Most normally, this service principal gets provisioned into a tenant after a user from that tenant has consented to use the app as a part of the login experience.
If you are trying to use user context (authorization code grant flow) to retrieve details about a tenant, you must ensure that that user is present in the directory you are trying to query. For example a user U can exist in their home tenant T1. If you try to query another tenant T2 using that user account, you will get any number of errors describing that the user account does not exist etc. You can remedy this by creating a guest account for U in T2, in which case there will be a brand new user object created in T2 which links to the original user object in T1. None the less, the user object should always be present in the tenant you are trying to query.
If you are trying to sign into an application with a user account that is in T1 and T2, you need to be sure to specify the tenant you want to actually get the token for. By default, if you use the common endpoint, you will get a token for the users home tenant. However, it is perfectly valid to get a token for the secondary tenant, as long as you specify that to our Token Service when making the request.
Finally the client application you use to make these requests needs to have the right permissions to the Graph API if you want to make specific calls to the Graph API. Every tenant needs to individually consent to the application in their tenant context in order to provision the correct permissions to their application.
With those principals in mind:
The error you are getting with "unauthorized_client" seems to be an issue with application provisioning in the secondary tenant. Please make sure to first login to the application with a user from the secondary tenant, and make sure that user has the correct permissions to consent to your app (a tenant admin is best here).
For the second issue with "Invalid domain name in the request url" please try using some hints here.
Specifically this:
By using the myOrganization alias. This alias is only available when using OAuth Authorization Code Grant type (3-legged) authentication; that is, when using a delegated permission scope. The alias is not case sensitive. It replaces the object ID or tenant domain in the URL. When the alias is used, Graph API derives the tenant from the claims presented in the token attached to the request. The following URL shows how to address the users resource collection of a tenant using this alias:
https://graph.windows.net/myorganization/users?api-version=1.6.
I hope this puts you on the correct path to resolve most of your issues.
There are issues with sandbox accounts and Azure. Access to the Azure Management Portal for the sandbox isn't straightforward and at this time does not work properly. I had to create a free Azure account with my hotmail account, then link AD from the new account to my sandbox AD to bypass the bug. When adding a new directory to the new Azure account, select "Use existing directory", sign out, then sign into the sandbox account you want to link it to. Then create your app from the new account.
After getting my app setup properly and new credentials, I had to enable pre-consent with the instructions listed at the end of: https://github.com/Microsoft/Partner-Center-Explorer
Lastly, I had to login to the Graph API with the customers ID, but with the resellers credentials.
The scenarios on the Partner Center SDK website include a section "Manage user accounts and assign licenses" under the "Manage customer accounts" section.
These samples include creating users and assigning licenses and a link to a console test app.
As an aside, a new version of the Partner Center SDK has just become available here. It was released on July 5th. While there is no official change history that I can find, I can see that it includes some new classes such as CustomerUser. You may find it easier to use that library rather than hitting the REST API (depending on how much work you've already done).

Resources