In a default Microsoft Entra ID tenant, any user can approve a third-party app that reads their mailbox, and nobody in IT is asked. If you have never reviewed this setting, assume some grants already exist and audit them before you change the policy.
What the default allows
A user can consent to an app reading their own mailbox. They cannot give an app unfettered read and write access to all files in the organisation, because that needs an administrator. Microsoft recommends allowing user consent only for apps from a verified publisher, to reduce the risk of malicious apps tricking users into granting access.
A grant is also not a password. Under OAuth 2.0 (RFC 6749) the app receives an access token with a defined scope and lifetime, issued instead of the user's credentials. The grant is its own object, and you have to find and remove it.
List what has been granted
You need at least the Cloud Application Administrator or Application Administrator role. In the Microsoft Entra admin center, go to Entra ID > Enterprise apps > All applications, select the app and open Permissions. The Admin consent tab shows permissions granted for the whole organisation. The User consent tab shows what specific users or groups granted.
The portal works app by app, so a tenant-wide view needs a loop. The Graph endpoints in the Microsoft revocation guidance are scoped to one service principal each: oauth2PermissionGrants returns delegated permissions and appRoleAssignments returns application permissions. The script below uses the equivalent cmdlets and resolves IDs to names, including application roles such as Mail.Read:
Connect-MgGraph -Scopes "Application.ReadWrite.All","DelegatedPermissionGrant.ReadWrite.All","AppRoleAssignment.ReadWrite.All"
$sps = Get-MgServicePrincipal -All
$name = @{}
$role = @{}
foreach ($s in $sps) {
$name[$s.Id] = $s.DisplayName
foreach ($r in $s.AppRoles) { $role["$($s.Id)|$($r.Id)"] = $r.Value }
}
$rows = @()
foreach ($g in Get-MgOauth2PermissionGrant -All) {
$rows += [pscustomobject]@{ App=$name[$g.ClientId]; Type="Delegated"
Resource=$name[$g.ResourceId]; Detail=$g.Scope }
}
foreach ($sp in $sps) {
$assigned = Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $sp.Id -All |
Where-Object { $_.PrincipalType -eq "ServicePrincipal" }
foreach ($a in $assigned) {
$rows += [pscustomobject]@{ App=$sp.DisplayName; Type="Application"
Resource=$name[$a.ResourceId]; Detail=$role["$($a.ResourceId)|$($a.AppRoleId)"] }
}
}
$rows | Export-Csv consent-audit.csv -NoTypeInformation
These scopes come from Microsoft's revocation examples and include write access, which a read-only audit does not need. Request narrower scopes if your tenant allows it, and test the script on a small set first.
Triage order
This order is ours, not Microsoft guidance. Start with delegated grants whose scopes read or send mail or read files. Filter the Detail column for Mail and Files. Then take every application permission.
A malicious grant looks ordinary in the portal, with a plausible name and a few scopes. Several users consenting to the same unfamiliar app, from a publisher you cannot verify, is the pattern to look for. If you find one, treat it as an incident and involve our incident response team or your own.
Remove risky grants
For permissions granted by admins, open the Admin consent tab, select the ... control beside the permission and choose Revoke permission. You cannot revoke anything on the User consent tab in the portal. For those you need Graph or PowerShell.
In Graph, delete a delegated grant by its ID, or remove an application permission by its assignment ID:
DELETE https://graph.microsoft.com/v1.0/oAuth2PermissionGrants/{id}
DELETE https://graph.microsoft.com/v1.0/servicePrincipals/{resource-servicePrincipal-id}/appRoleAssignedTo/{appRoleAssignment-id}
The revocation page also has PowerShell scripts that remove all delegated and application permissions of one app. Read them before running them, because they strip everything for that service principal.
Revoking does not stop a user approving the same app again. Microsoft names two remedies: stop the app requesting the permissions through dynamic consent, or block user consent altogether. For third-party apps you cannot change what they request, so in our view blocking is the control you own.
Restrict user consent
You need the Privileged Role Administrator role. The Global Administrator role is only required if you use the admin center, where the setting is under Identity > Applications > Enterprise apps > Consent and permissions > User consent settings.
Entra ships two built-in policies for this:
| ID | Effect |
|---|---|
microsoft-user-default-low | Users consent only to apps from verified publishers or registered in your tenant, and only for permissions you classify as low impact |
microsoft-user-default-legacy | Users consent to any permission that does not need admin consent, for any application |
The low policy depends on you classifying permissions, which is how you select what users may approve. Do that first, then test with an ordinary user account.
Before you change anything in PowerShell or Graph, retrieve the current authorizationPolicy. Your tenant may have ManagePermissionGrantsForOwnedResource.* policies assigned, such as the one that lets developers manage consent for apps they own. Keep them in the collection or you will remove them. Disabling user consent with Graph PowerShell looks like this:
Connect-MgGraph -Scopes "Policy.ReadWrite.Authorization"
$body = @{
"permissionGrantPolicyIdsAssignedToDefaultUserRole" = @(
"managePermissionGrantsForOwnedResource.{other-current-policies}"
)
}
Update-MgPolicyAuthorizationPolicy -BodyParameter $body
To allow consent under the low-impact policy instead, add managePermissionGrantsForSelf.microsoft-user-default-low to the Graph PATCH of defaultUserRolePermissions.permissionGrantPoliciesAssigned. A policy change only affects future consent, so existing grants stay in place until you remove them.
Give users a way to ask
If you block consent with no alternative, users will look for workarounds. The admin consent workflow lets them request approval instead. A Global Administrator turns it on under Entra ID > Enterprise apps > Consent and permissions > Admin consent settings. Set "Users can request admin consent to apps they are unable to consent to" to Yes, then choose:
- Reviewers: users, groups or roles. Being a reviewer does not raise their privileges, so each must already hold the permissions to grant consent for the requested app. Only Global Administrators can approve apps requesting Microsoft Graph app roles (application permissions).
- Email notifications: if you disable them for reviewers, requester notifications are disabled too.
- Request lifetime and expiration reminders: the lifetime is the number of days a request stays valid. The first reminder arrives at roughly the midpoint, so day two for a three-day request.
Save, then allow up to an hour for the workflow to take effect. A removed reviewer keeps access to requests made while they held the role. New reviewers cannot act on requests created before they were added.
Entra built-in roles, Exchange RBAC and Teams resource-specific consent can also grant access, so include them in a wider review.
Where to start
- Run the inventory script and review delegated grants and application permissions as separate lists. Mark the apps nobody can justify.
- Revoke the risky grants: admin-consented ones in the portal, user-consented ones through Graph or PowerShell.
- Read the current
authorizationPolicy, then set user consent tomicrosoft-user-default-lowwith classified permissions, or disable it, keeping theManagePermissionGrantsForOwnedResource.*entries. - Enable the admin consent workflow. Name reviewers whose roles can grant consent for what users will ask for, and keep a Global Administrator among them, because only that role approves Microsoft Graph application permissions.
- Repeat the review on a schedule. If you lack the time, our consulting team can run it as an assessment, and our managed security service can cover monitoring.
