AccuroAI
Products
What We Do
Solutions
Company
Resources
Book demo
← Blog·How-To9 read

How to Audit AI App OAuth Grants in Microsoft 365 and Google Workspace

Four token-theft incidents in twelve months never touched a password. The six-step audit — inventory, scope classification, ghost grants, revocation, consent lockdown, continuous diff — with every command taken from Microsoft's and Google's documentation.

S
Sofia Reyes
Head of Compliance
2026-08-20

Four times in the last twelve months, attackers walked into large companies' Salesforce, Google Workspace and Microsoft 365 data without touching a password or an MFA prompt. They used OAuth tokens a third-party app was holding — Salesloft's Drift AI chat agent in August 2025, Gainsight in November, Context.ai's abandoned AI office suite in April 2026, and, as reported by Nudge Security, Klue in June. Salesforce's own advisory on the Gainsight case says the quiet part: the incident "was not the result of a vulnerability in the Salesforce platform itself." The platform did exactly what the consent screen said it would, months or years earlier.

AI apps make this worse for a structural reason: they ask for broad scopes (read all your mail, all your files) because that is what makes them useful, employees grant them in a hurry, and nobody revokes them. Material Security's June 2026 study of 22,332 OAuth apps across 21 Google Workspace environments found that 91% of the AI and automation apps had first appeared since January 2024, that 47% of all apps had not been used in 90 days, and that 1,064 apps still held live tokens for users who had left the company. This is the audit that finds your version of those numbers. Every command and path below is taken from Microsoft's and Google's current documentation.

Step 1 — Inventory every grant

Microsoft 365 / Entra ID

Delegated grants (what users consented to) live in oauth2PermissionGrants; application permissions (what admins granted to the app itself) live in appRoleAssignments. Pull both.

Connect-MgGraph -Scopes "Directory.Read.All"
Import-Module Microsoft.Graph.Identity.SignIns
Get-MgOauth2PermissionGrant -All | Select-Object ClientId, ConsentType, PrincipalId, Scope

ConsentType tells you the blast radius: AllPrincipals is a tenant-wide admin consent; Principal is one user. Resolve ClientId to a name with Get-MgServicePrincipal, and pull application permissions per app with Get-MgServicePrincipalAppRoleAssignment. Over Graph directly: GET https://graph.microsoft.com/v1.0/oauth2PermissionGrants, which needs Directory.Read.All; Microsoft notes the endpoint can lag for recently created grants unless you filter on clientId. In the portal, Entra ID → Enterprise apps → All applications → the app → Permissions, with separate Admin consent and User consent tabs.

Google Workspace

The admin console shows grants per app under Security → Access and data control → API controls → Manage Third-Party App Access, but the bulk view is GAM:

gam all users print tokens todrive
gam user jane@example.com show tokens

The export gives you user, client ID, display name and scopes per grant; add gcpdetails for the publishing project. Turn on OAuth log events (Reporting → Audit and investigation → OAuth log events) before you start, so you can see Authorize and Revoke events as you work; API call events need Enterprise Standard or Plus, Education Standard or Plus, or Cloud Identity Premium.

Step 2 — Classify scopes, not app names

The app's name tells you nothing about exposure; the scope string tells you everything. Use the vendors' own categories.

Google restricted scopes — the ones that require a security assessment for the app publisher: https://mail.google.com/ ("Read, compose, send, and permanently delete all your email from Gmail"), gmail.readonly, gmail.modify, gmail.compose, gmail.insert, gmail.metadata, gmail.settings.basic, gmail.settings.sharing; https://www.googleapis.com/auth/drive ("View and manage all your Drive files"), drive.readonly, drive.metadata, drive.metadata.readonly, drive.activity. An AI note-taker that asks for full drive rather than drive.file ("Create new Drive files, or modify existing files, that you open with an app") has asked for every document in the company.

Microsoft Graph — flag any grant containing Mail.ReadWrite, Mail.Read, Mail.Send, Files.ReadWrite.All, Files.Read.All, Sites.ReadWrite.All, Chat.ReadWrite, Directory.ReadWrite.All or Directory.AccessAsUser.All; as application permissions these operate "without a signed-in user" across every mailbox or site. And look for offline_access: it "gives your app access to resources on behalf of the user for an extended time" via a refresh token "typically valid for 90 days", and it is granted implicitly alongside any delegated permission. Every long-lived token in the incidents above was an offline_access-style refresh token.

Microsoft's own managed default for user consent is a good reference list of what ordinary users should not be able to grant alone: it blocks Files.Read.All, Files.ReadWrite.All, Sites.Read.All, Sites.ReadWrite.All, the Mail.* family, Calendars.*, Chat.*, OnlineMeetings.*, MailboxSettings.*, Contacts.*, Tasks.* and People.Read.

Step 3 — Find the AI apps, and the ghosts

Three filters surface most of the risk:

  • Unverified publishers with high-severity scopes. In the Defender portal under Cloud Apps → OAuth apps, filter on "Permission level: high severity" and "Community use: not common", and use the saved query for apps authorised by external users. App governance, if licensed, extends the same view across Entra, Google and Salesforce.
  • Dormant grants. Join the grant list to sign-in or API-call logs and flag anything with no activity in 90 days — in Material's data, almost half of all apps.
  • Departed users. Join PrincipalId (or the GAM user column) to your HR leaver list. A deprovisioned user's tokens are not automatically revoked in every configuration; Context.ai's token into Vercel came from a self-service trial nobody had cleaned up, at a company that "wasn't even a registered customer".

Name patterns help — "AI", "GPT", "assistant", "copilot", "notetaker", "summarise" — but the scope-first view catches the AI app that called itself a CRM helper.

Step 4 — Revoke, and understand what revocation does not do

Microsoft

The portal cannot revoke user-consented permissions; Microsoft's documentation says so and points you to Graph or PowerShell. The documented script:

Connect-MgGraph -Scopes "Application.ReadWrite.All","Directory.ReadWrite.All","DelegatedPermissionGrant.ReadWrite.All","AppRoleAssignment.ReadWrite.All"
$sp = Get-MgServicePrincipal -ServicePrincipalID "<ServicePrincipal objectID>"
Get-MgOauth2PermissionGrant -All | Where-Object { $_.clientId -eq $sp.Id } |
  ForEach-Object { Remove-MgOauth2PermissionGrant -OAuth2PermissionGrantId $_.Id }
Get-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $sp.Id -All |
  Where-Object { $_.PrincipalType -eq "ServicePrincipal" } |
  ForEach-Object { Remove-MgServicePrincipalAppRoleAssignedTo -ServicePrincipalId $sp.Id -AppRoleAssignmentId $_.Id }

Microsoft's caveat, verbatim: "Revoking the current granted permission doesn't stop users from re-consenting to the application's requested permissions." Revocation without Step 5 is a loop.

Google

gam all users delete token clientid <ClientID>

During the Context.ai incident, Wiz's guidance was exactly this — revoke the app's client ID for every user, rotate credentials, then review Drive, Gmail and login audit logs for what the token had touched. Blocking the app in App access control prevents re-authorisation tenant-wide.

Step 5 — Close the front door

Entra: Identity → Applications → Enterprise apps → Consent and permissions → User consent settings. Move from "allow user consent for apps" to the verified-publisher, low-impact policy (microsoft-user-default-low) or to Microsoft-managed defaults, then turn on the admin consent workflow (Admin consent settings → "Users can request admin consent to apps they are unable to consent to") with named reviewers and an expiry. Note Microsoft's warning: "Any updates to user consent settings only affect future consent operations for applications. Existing consent grants remain unchanged" — which is why Step 4 comes first. Requests land under Enterprise apps → Activity → Admin consent requests, where Block "creates a service principal object for the application in your tenant in a disabled state".

Google: in API controls, set "Unconfigured third-party apps" to block, or to allow only apps that request basic sign-in information; mark the apps you have reviewed as Trusted or Limited (Limited means "Restricted to unrestricted Google services only"); restrict the Gmail and Drive services at scope level so that even a trusted app cannot get full-mailbox scope without a second decision.

Step 6 — Make it continuous

One audit finds the backlog. What keeps it from growing is a monthly job that re-runs Step 1, diffs against last month, and opens a ticket for every new high-severity grant, every grant whose user has left, and every app with no activity in 90 days; OAuth log events on Google and Defender's OAuth app policies on Microsoft can raise the alert the same day. The broader point is that OAuth grants are only one of the ways AI reaches your data — browser sessions, desktop apps, coding assistants and MCP servers are the others — and the same inventory discipline applies to all of them. If you already run an AI discovery tool, feed it the grant export; if you do not, this audit is usually the moment people realise they need one.

FAQ

How often should we audit OAuth grants?

Monthly for the diff, quarterly for a full review of high-severity grants with their business owners. After any third-party breach notice, immediately — revoke the named client IDs first and investigate second, as the Drift and Context.ai responders did.

It moves approval to a reviewer. With the admin consent workflow on, users request and a named admin approves, typically within a day. Microsoft's managed default still lets users consent to low-impact scopes from verified publishers, which covers most legitimate requests.

Does deprovisioning a user revoke their OAuth grants?

Not reliably, and refresh tokens held by third parties can outlive the account in some configurations. Treat leaver grants as a separate audit join, not a side-effect of offboarding.

What about grants into Salesforce and other SaaS?

Same pattern, different console. Three of the four incidents above were Salesforce connected apps. Defender app governance covers Salesforce alongside Entra and Google; otherwise use each platform's connected-app report and the same scope-first classification.

Sources: Microsoft Graph, list oauth2PermissionGrants · Microsoft Learn, review and revoke application permissions · Microsoft Learn, configure user consent (updated 4 Aug 2026) · Microsoft Learn, app consent policies (22 Jan 2026) · Microsoft Learn, admin consent workflow · Microsoft Learn, offline_access and OIDC scopes · Microsoft Graph permissions reference · Microsoft Learn, investigate risky OAuth apps (updated 18 Jul 2026) · Google Workspace, control third-party app access · Google Workspace, OAuth log events · GAM, user tokens · Gmail API scopes · Drive API scopes · Google Threat Intelligence on Salesloft Drift (27 Aug 2025) · Salesforce advisory on Gainsight (24 Nov 2025) · Wiz on the Context.ai token compromise (20 Apr 2026) · Push Security on the Vercel breach (23 Apr 2026) · Nudge Security on Klue (23 Jun 2026) · Material Security, OAuth Risk Report (24 Jun 2026).

Related: Shadow AI Discovery · Agent Scope Creep: Tool Access Bigger Than You Think · Ghost Agents: The AI Agent Offboarding Problem Nobody Owns.

See AccuroAI in action.
30-minute demo tailored to your top AI risk.
Book a demo
More from the blog
See AccuroAI in action.

Book a 30-minute demo and see how security teams use AccuroAI to discover, govern, and protect every AI asset across their organization.

Book a demoTalk to security