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.
Related
I have a question regarding a multi-tenant App Registration in Azure AD. The first time a user logs in through the app it will ask him to grant his consent to access some of his data if necessary or ask an administrator to grant a tenant level consent. This is just fine.
But what if a change is made to the App Registration (Logout URL modified for example)? Is it possible that the users that never used the app registration already will need to grant their consent or that a tenant administrator might need to give his consent again?
Changing your redirect URLs or logout URL will not cause the consent to be prompted for again.
Changing the configured permissions also won't cause users who have already granted consent to have to grant consent again (but the app will only have the permissions it had been originally granted).
Users will only be prompted for consent in the following situations:
If your application dynamically requests a permissions which has not been granted (e.g. scope=https://graph.microsoft.com/Mail.Read, if Mail.Read has not been granted.
If your application requests access to ".default" for a resource, and no permissions have been granted for that resource. For example, if you application requests scope=https://graph.microsoft.com/.default and no delegated permissions for Microsoft Graph have been granted, the user will be prompted for consent (for all permissions configured in the app registration). If any permission for the requested resource have been granted, the user will not be prompted for consent.
If your application forces user consent using prompt=consent. Don't do this—there is almost no situation where this is necessary. (Read a lot more on this at https://stackoverflow.com/a/60151790/325697.)
Yes. If you modify properties such as redirect url, permissions, logout url and so on, you have to make admins from other tenant do the admin consent again to make it effective.
Using admin consent url is the quickest way:
https://login.microsoftonline.com/{tenant-id}/adminconsent?client_id={client-id}
I am going to consent only specific admin permissions in graph api.
But it requests all tenant permissions.
Current logic is
Get delegated token by authorization.
https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/authorize?client_id={CLIENT_ID}&response_type=token&redirect_uri={LOGIN_REDIRECT_URI}&response_mode=form_post&scope=offline_access https://graph.microsoft.com/.default
Prompt admin consent
https://login.microsoftonline.com/{TENANT_ID}/adminconsent?client_id={CLIENT_ID}&redirect_uri=http://localhost/team-members/getAppToken&scope=https://graph.microsoft.com/calendars.readwrite
Get application token
https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token?scope=https://graph.microsoft.com/calendars.readwrite
In this logic, admin consent is always asked all permissions in 2), but I want to ask only the permission Calendars.ReadWrite.
How to ask to consent for a specific permissions?
This is related to your permission type. If your permission is a delegated permission, you can dynamically agree to a specific delegated permission on the administrator consent page: scope=https://graph.microsoft.com/calendars.readwrite.
If your permissions are application permissions, you can only request the static /.default scope, which will require the administrator to consent to all permissions in the tenant: scope=https://graph.microsoft.com/.default.
See the document, there are detailed instructions:
At this point, Azure AD requires a tenant administrator to sign in to
complete the request. The administrator is asked to approve all the
permissions that you have requested in the scope parameter. If you've
used a static (/.default) value, it will function like the v1.0 admin
consent endpoint and request consent for all scopes found in the
required permissions (both user and app). In order to request app
permissions, you must use the /.default value. If you don't want
admins to see a given permission in the admin consent screen all the
time when you use /.default, the best practice is to not put the
permission in the required permissions section. Instead you can use
dynamic consent to add the permissions you want to be in the consent
screen at run time, rather than using /.default.
If you login to Azure portal and find your application
https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredApps
Click on API Permissions tab
You will see all configured permissions for Microsoft Graph API.
Ensure that there is only Calendars.ReadWrite by removing all redundant permissions.
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.
I'm hoping someone has some insight into an issue I'm having with a newly registered app within Microsoft's Azure Portal (portal.azure.com).
My issue on login when I get the following dialog
The error code and message appears in the lower right corner;
AADSTS90094: This operation can only be performed by an administrator. Sign out and sign in as an administrator or contact one of your organization's administrators.
Configuration-wise, I believe I have this setup to not require admin consent, however there maybe something I'm missing.
My app is configured with;
Id Token, single tenant (web) application
Delegated, user consent permissions with no admin permissions
With the enterprise application, the configuration is set to;
Enabled for users to sign-in: Yes
User assignment required: Yes
Visible to users: Yes
4 users have been added with the Default Access role
Allow users to request access to this application: No (as they are assigned)
Last of all, within the azure directory itself under the Enterprise applications - User settings configuration I have set the company data user consent to Yes
When I navigate to either my application URL, or from the app within myapps.microsoft.com, both give me the above dialog requesting an admin consent.
I don't want to grant admin consent if not required, as it seems a bit like using a sledgehammer to solve the problem.
I feel like I'm either missing something big, or doing something silly - please help, and let me know if I can provide further information.
Edit 1.1:
My authentication request URL is: https://login.microsoftonline.com/<tenantid>/oauth2/v2.0/authorize?client_id=<clientid>&redirect_uri=<redirecturi>&response_mode=form_post&response_type=code id_token&scope=openid email profile offline_access User.Read User.ReadBasic.All Mail.ReadWrite&state=OpenIdConnect.AuthenticationProperties=<gibberish>&nonce=<gibberish>&x-client-SKU=ID_NET461&x-client-ver=5.4.0.0
(I'm using ASP.NET MVC combined with Microsoft's OpenId Connect authentication library)
When a user consents to an application which does not require assignment (in a tenant where user consent is allowed, and for an application requesting only permissions which do not require admin consent), two things happen:
Consent grants are recorded for the app, the user and the delegated permissions being requested.
The user is assigned to the app at a "default" app role.
The second step may seem surprising, but it serves a simple role: it ensures the user sees apps they've consented to in the Azure AD Access Panel (https://myapps.microsoft.com). (The Azure AD Access Panel will show a user all apps they are assigned to.)
It would defeat the purpose of the "user assignment is required" control if users could cause themselves to be assigned by triggering user consent. So, currently, when an application is set to require user assignment, users are simply not allowed to consent to the application.
Today, you have two options:
Ask an admin to grant tenant-wide consent for the application (e.g. Enterprise apps > Permissions > Grant admin consent, or App Registrations > API Permissions > Grant admin consent).
Configure the app to not require user assignment, and update the app's code to require the user be assigned to an app role by checking the "roles" claim.
From below, what I infer is when the application is configured with Delegated Permissions it makes all requests on behalf of the signed-in user.
So, under Delegated Permissions, again we have "Access the directory as the signed-in user" option listed. What does this actually do?
Application Permissions: Your client application needs to access the
Web API directly as itself (no user context). This type of permission
requires administrator consent and is also not available for Native
client applications.
Delegated Permissions: Your client application needs to access the Web
API as the signed-in user, but with access limited by the selected
permission. This type of permission can be granted by a user unless
the permission is configured as requiring administrator consent.
So, under Delegated Permissions, we have "Access the directory as the
signed-in user" option listed. What does this actually do?
In very simple words, the application essentially impersonates you (or the logged in user) in case of delegated permissions.
To give you an example, let's say you created a web application in your Azure AD with delegated permissions to access Azure Service Management API. Now when you login into this application and try to access your Azure resources (storage accounts, VMs etc.), the application will only be able to do things you're granted permission to do in that Azure subscription. For example, if you're in Reader role in your Azure subscription (i.e. you can't create/update/delete resources). If you try to create a resource through your application you will get an error back because the application is impersonating you.
Delegated permissions require a user to login to Azure AD and present the resulting authentication token to your application. Your application can make calls by passing your client id, secret (if applicable) and the user's authentication token. Your application's effective permissions will be the lowest combination of the user and your application. For example, if your application has been granted read/write to a resource but the user only has read, your effective permissions are read. The same is true if the user has read/write but the application only has read.
Application permissions do not require a user to login. Just your client id and secret are enough. If you do not have application permissions and attempt to access the api without also presenting an authenticated user's token you will receive 401 errors.