czmiel24
czmiel24

Reputation: 75

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?

Upvotes: 4

Views: 12407

Answers (2)

Philippe Signoret
Philippe Signoret

Reputation: 14336

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:

  1. 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.
  2. 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).
  3. 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:

  1. 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.
  2. 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:

  1. Perform a sign in without prompt=consent.
  2. 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.

Upvotes: 3

Joey Cai
Joey Cai

Reputation: 20067

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.

enter image description here

Users will be blocked from granting consent to the application, and they will be told to ask their admin for access to the app.

enter image description here

For more details, you could refer to this article.

Upvotes: 1

Related Questions