To stop illicit consent grants in Microsoft Entra ID, restrict user consent under Enterprise apps > Consent and permissions > User consent settings so users can only approve low-impact permissions (or nothing at all), and turn on the admin consent workflow so every other request goes to a named reviewer. Then review the grants that already exist, because changing the setting does not remove consent that users have given in the past.
Who this is for and what you will have
This guide is for Microsoft Entra and Microsoft 365 administrators who want to close the OAuth consent phishing path: an attacker registers an app, sends users a link, and a user clicks Accept on a consent prompt that hands the app access to mail, files or contacts.
At the end you will have:
- A user consent setting that matches your risk appetite, with the reasoning written down.
- Permission classifications that define which delegated permissions count as low impact.
- An admin consent workflow with reviewers, notifications and an expiry period.
- A repeatable process for finding questionable consent grants and revoking them.
Consent control is one part of an identity-first security model; the zero trust remote access architecture describes how it fits with device and network controls. Apps your own developers register carry a different risk, which is covered in finding expiring app secrets and certificates.
How an illicit consent grant works
Microsoft describes the attack in three steps. The attacker registers an application in Microsoft Entra ID that requests access to data such as contact information, email or documents. The attacker then uses phishing, or code injected into a trusted website, to get a user to consent. After consent, the app has account-level access to that user's data without needing an account in your organization.
The important consequence is that normal incident response does not work. Resetting the password or enforcing MFA does nothing, because the app is not signing in as the user with a password; it holds its own grant. The only fixes are to prevent the consent in the first place and to revoke grants that already exist.
Two permission types matter:
| Permission type | Who can consent | What the app can do |
|---|---|---|
| Delegated permission | A user (if policy allows) or an admin | Act as the signed-in user, within that user's access |
| Application permission (app role) | Admins only | Act as itself, with no signed-in user, often across the whole tenant |
Illicit consent attacks usually target delegated permissions, because those are the ones ordinary users can approve. Admin consent is the bigger prize, which is why the reviewer process below matters as much as the user setting.
Prerequisites
| Task | Minimum role documented by Microsoft |
|---|---|
| Change user consent settings | Privileged Role Administrator (Global Administrator when using the admin center) |
| Classify permissions | Application Administrator or Cloud Application Administrator |
| Turn on the admin consent workflow | Global Administrator |
| Review and revoke granted permissions | Cloud Application Administrator or Application Administrator |
| Review admin consent requests | Cloud Application Administrator who is a designated reviewer |
For the PowerShell steps, install the Microsoft Graph PowerShell SDK. The consent cmdlets are in the Microsoft.Graph.Identity.SignIns module.
Step 1: Choose a user consent setting
Sign in to the Microsoft Entra admin center and browse to Entra ID > Enterprise apps > Consent and permissions > User consent settings. Under User consent for applications, pick one of the options and select Save.
| Option | What users can approve | Trade-off |
|---|---|---|
| Do not allow user consent | Nothing new; only apps already consented to or approved by an admin | Highest control, more admin workload |
| Allow user consent for apps from verified publishers, for selected permissions | Apps from verified publishers or registered in your tenant, and only permissions you classify as low impact | Requires you to maintain permission classifications |
| Let Microsoft manage your consent settings | Any user-consentable delegated permission except a Microsoft-maintained list of sensitive ones | Microsoft updates the rules over time; default for new tenants |
| Allow user consent for apps | Any permission that doesn't need admin consent, for any app | The setting illicit consent attacks rely on |
Microsoft's guidance is to allow user consent only for apps from verified publishers. The Microsoft-managed policy currently blocks user consent for Microsoft Graph permissions such as Files.Read.All, Sites.Read.All, Mail.Read, Mail.ReadWrite, Calendars.Read, Chat.Read and People.Read, plus the Exchange Online EWS.AccessAsUser.All, IMAP.AccessAsUser.All, POP.AccessAsUser.All and EAS.AccessAsUser.All permissions. A companion policy lets users consent to mail permissions for a short list of named mail clients.
One detail that surprises people: if an application requires user assignment, its permissions must be consented to by an administrator even when your user consent policy would otherwise allow it.
Set it with Microsoft Graph PowerShell
The setting lives in the tenant authorization policy, in defaultUserRolePermissions.permissionGrantPoliciesAssigned. Values use the format managePermissionGrantsForSelf.{policy-id}, and an empty list means user consent is disabled. Microsoft warns that the same collection can contain managePermissionGrantsForOwnedResource.* entries, which let developers manage consent for apps they own, so read the current value first and keep those entries.
Connect-MgGraph -Scopes "Policy.ReadWrite.Authorization"
# Read what is assigned today
$current = (Get-MgPolicyAuthorizationPolicy).DefaultUserRolePermissions.PermissionGrantPoliciesAssigned
$current
# Keep any owned-resource policies, replace the user consent policy
$keep = @($current | Where-Object { $_ -like 'managePermissionGrantsForOwnedResource.*' })
$body = @{
defaultUserRolePermissions = @{
permissionGrantPoliciesAssigned = @('managePermissionGrantsForSelf.microsoft-user-default-low') + $keep
}
}
Update-MgPolicyAuthorizationPolicy -BodyParameter $bodyTo disable user consent entirely, assign only the $keep entries. To list the built-in and custom policies you can reference, run Get-MgPolicyPermissionGrantPolicy | Format-Table Id, DisplayName after connecting with the Policy.ReadWrite.PermissionGrant scope.
Step 2: Classify low-impact permissions
The verified-publisher option only lets users consent to permissions you classify as low impact. Microsoft supports Low, Medium (preview) and High (preview) classifications, and only delegated permissions that don't require admin consent can be classified.
In the admin center, browse to Entra ID > Enterprise apps > Consent and permissions > Permission classifications, choose the tab, select Add permissions, pick the API and select the delegated permissions. Microsoft lists openid, profile, email and offline_access as the minimum for basic sign-in, which makes them a sensible starting set.
Connect-MgGraph -Scopes "Policy.ReadWrite.PermissionGrant", "Application.Read.All"
$graph = Get-MgServicePrincipal -Filter "displayName eq 'Microsoft Graph'"
foreach ($name in 'openid', 'profile', 'email', 'offline_access') {
$scope = $graph.Oauth2PermissionScopes | Where-Object { $_.Value -eq $name }
$params = @{
PermissionId = $scope.Id
PermissionName = $scope.Value
Classification = 'Low'
}
New-MgServicePrincipalDelegatedPermissionClassification -ServicePrincipalId $graph.Id -BodyParameter $params
}
Get-MgServicePrincipalDelegatedPermissionClassification -ServicePrincipalId $graph.IdResist adding read access to mail, files or chat to the low list. Those are exactly the permissions consent phishing apps ask for.
Step 3: Turn on the admin consent workflow
Blocking consent without an approval path pushes users toward workarounds. The admin consent workflow replaces the dead end with an Approval required prompt where the user types a justification and selects Request approval.
- In the Microsoft Entra admin center, browse to Entra ID > Enterprise apps > Consent and permissions > Admin consent settings.
- Under Admin consent requests, set Users can request admin consent to apps they are unable to consent to to Yes.
- In Who can review admin consent requests, add users, groups or roles. Use a small group of people who actually hold an admin role that can grant consent.
- Turn on Selected users will receive email notifications for requests and Selected users will receive request expiration reminders.
- Set Consent request expires after (days).
- Select Save. Microsoft states it can take up to an hour for the workflow to become enabled.
Two documented limitations are worth knowing. Reviewers removed from the list can still review requests created while they were reviewers, and new reviewers are not assigned to requests created before they were added. If a user sends several requests for the same app, only the first is submitted.
Step 4: Review requests safely
Reviewers work from Entra ID > Enterprise apps > Activity > Admin consent requests, on the My Pending tab. The All (Preview) tab is history only.
For each request, open Review permissions and consent, the App details tab and the Requested by tab, then choose:
| Action | Effect |
|---|---|
| Approve | Grants admin consent; every requester is notified and all users in the tenant can use the app unless you require user assignment |
| Deny | Requires a justification that all requesters see; users can request again later |
| Block | Requires a justification; creates a disabled service principal for the app so users can't request it again |
Before approving, check that you know who controls the app and why it needs each permission. Microsoft lists role management, full access to all mailboxes or all sites, and full user impersonation as examples of highly privileged operations that tenant-wide consent can unlock. If the app only needs a few users, approve it and then set Assignment required on the enterprise app so only assigned users can sign in.
Step 5: Find consent grants that already exist
Changing the settings protects you from now on. To find grants made before that, use three sources.
Audit log
In the Microsoft Defender portal, open Audit (https://security.microsoft.com/auditlogsearch), run a search for your date range, sort the Activity column and look for Consent to application. Open each entry and check whether IsAdminConsent is True; an unexpected True means someone with admin rights granted broad access. Microsoft notes that audit entries can take 30 minutes to 24 hours to appear, and suggests reviewing consent grants weekly in large tenants.
Grant inventory with PowerShell
The following lists every delegated grant with the client app name, so you can sort by consent type and scope. AllPrincipals grants cover every user in the tenant and deserve the closest look when the app isn't from Microsoft.
Connect-MgGraph -Scopes "Application.Read.All", "Directory.Read.All"
$grants = Get-MgOauth2PermissionGrant -All
$grants | ForEach-Object {
$client = Get-MgServicePrincipal -ServicePrincipalId $_.ClientId -Property DisplayName, AppId, PublisherName
[pscustomobject]@{
App = $client.DisplayName
AppId = $client.AppId
Publisher = $client.PublisherName
ConsentType = $_.ConsentType
PrincipalId = $_.PrincipalId
Scope = $_.Scope
}
} | Sort-Object ConsentType, App | Export-Csv .\delegated-grants.csv -NoTypeInformationLook for misspelled or generic app names, Read/Write/All scopes that don't fit the app's purpose, and grants by high-value users. Users can also review their own app access at https://myapps.microsoft.com.
Defender for Cloud Apps
If you license Microsoft Defender for Cloud Apps, go to Cloud Apps > OAuth apps in the Defender portal (or App governance, if it's turned on). Microsoft suggests filtering on Permission level high severity with Community use not common, and checking the saved query Apps authorized by external users. You can create an OAuth app policy under Cloud Apps > Policies > Policy management > Threat detection > Create policy > OAuth app policy to alert on, for example, high-permission apps authorized by many users. Built-in anomaly policies include Malicious OAuth app consent, Misleading OAuth app name and Misleading publisher name for an OAuth app.
Remediate a malicious app
When you confirm an app is illicit, revoke both kinds of grant. On the app's Permissions page you can revoke admin-consented permissions, but user-consented permissions can only be removed with Graph or PowerShell. The following script is based on Microsoft's revocation script. Application permissions are removed through the appRoleAssignedTo relationship of the resource service principal (the API, such as Microsoft Graph), which Microsoft recommends as the best practice, so the resource ID comes from each assignment:
Connect-MgGraph -Scopes "Application.ReadWrite.All", "Directory.ReadWrite.All", "DelegatedPermissionGrant.ReadWrite.All", "AppRoleAssignment.ReadWrite.All"
$sp = Get-MgServicePrincipal -ServicePrincipalId "<service principal object ID>"
# Remove all delegated grants
Get-MgOauth2PermissionGrant -All | Where-Object { $_.ClientId -eq $sp.Id } | ForEach-Object {
Remove-MgOauth2PermissionGrant -OAuth2PermissionGrantId $_.Id
}
# Remove all application permissions (app role assignments granted to the app)
Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $sp.Id -All |
Where-Object { $_.PrincipalType -eq "ServicePrincipal" } | ForEach-Object {
Remove-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $_.ResourceId -AppRoleAssignmentId $_.Id
}Revoking a grant doesn't stop users consenting again, so either block the app through the admin consent workflow or keep user consent restricted. Then use the audit log to scope what the app accessed; Microsoft notes that this depends on mailbox auditing and activity auditing being on before the attack.
Verification
- Sign in as a test user to an unverified multitenant test app that requests
Mail.Read. The user should see Approval required instead of a consent prompt. - Confirm the request appears on My Pending for a reviewer, and that denying it notifies the requester.
- Re-run
Get-MgPolicyAuthorizationPolicyand confirmPermissionGrantPoliciesAssignedcontains only the policies you intended. - Re-run the grant inventory a week later and compare.
Troubleshooting
AADSTS90094: Administrator consent is required. The app asks for permissions the user can't consent to under your policy and the admin consent workflow isn't on. Turn the workflow on, or grant consent as an admin after review.
AADSTS90095 (AdminConsentRequiredRequestAccess). This is the expected interrupt in the admin consent workflow that tells the user to ask an admin. It's working as designed.
AADSTS65001: The user or administrator hasn't consented to use the application. No consent record exists for the user and resource. If you disabled user consent, an admin must grant it.
A reviewer can't approve a request. Reviewers need a role that can grant the requested permissions. Requests for Microsoft Graph application permissions need a Global Administrator to approve.
Developers lost the ability to consent for their own apps. The managePermissionGrantsForOwnedResource.* entries were dropped when the authorization policy was updated. Add them back.
Checklist
- User consent set to verified publishers with selected permissions, Microsoft-managed, or disabled.
- Low-impact classification limited to sign-in permissions.
- Admin consent workflow on, with reviewers who can actually approve.
- Reviewers trained to use Block for untrusted apps.
- Weekly review of Consent to application audit events.
- Existing
AllPrincipalsand high-privilege grants inventoried and justified. - Removal script tested so revocation is fast during an incident.
References
- Configure how users consent to applications
- Manage app consent policies
- Overview of user and admin consent
- Configure permission classifications
- Configure the admin consent workflow
- Review and take action on admin consent requests
- Review permissions granted to enterprise applications
- Detect and remediate illicit consent grants
- Create policies to control OAuth apps
- Investigate and remediate risky OAuth apps
- Delete appRoleAssignedTo from a service principal
- defaultUserRolePermissions resource type
- Microsoft Entra authentication and authorization error codes