Est.

Scoping OAuth Permissions to Minimum Required Access

Most companies ask for far more OAuth access than their apps actually need.

Staff Writer · · 11 min read
Cover illustration for “Scoping OAuth Permissions to Minimum Required Access”
Auth and Security · August 26, 2026 · 11 min read · 2,553 words

OAuth scopes are the permission strings your app asks for when it wants access to something like Gmail, Drive, or a customer database. Scoping to minimum access means asking for exactly what the task needs and nothing more, and most companies are terrible at it. That's the whole article, honestly. Everything below is just the how and the why.

Quick vocabulary check before we go further, because OAuth loves to reuse words in confusing ways. A scope is not the same as a permission a user already has. Scopes limit what a token can do; they never expand it beyond what the person granting access already holds. There's also no universal scope dictionary. Unlike OpenID Connect, which standardizes a few common scopes, plain OAuth 2.0 leaves scope naming entirely up to whoever built the API. Google invents its own. Microsoft invents its own. Your internal API team invents its own, usually on a Friday afternoon, usually in a hurry.

That last part matters more than it sounds like it should. RFC 9700, the IETF's OAuth security guidance published in January 2025, rolls up years of prior advice (RFCs 6749, 6750, and 6819) into one document, kills off the Implicit flow and the Password grant, and makes PKCE mandatory for authorization code flows. Buried in there is a line worth tattooing somewhere: access token privileges "SHOULD be restricted to the minimum required for the particular application or use case." That's not a style suggestion. It's a leakage-mitigation strategy. Smaller scope means smaller damage if the token ends up somewhere it shouldn't.

And tokens do end up places they shouldn't. That's sort of the whole problem.

Where over-scoping actually comes from — the structural reasons teams over-request by default

Nobody sets out to build an insecure app. Over-scoping happens because asking for broad permissions once, up front, is easier than asking for the right permissions repeatedly, later. It's the software equivalent of packing your entire closet for a weekend trip because you don't want to think about outfits twice.

A few specific habits drive this:

Developers request "full access" scopes defensively, so they never have to go back and ask for more later. It feels efficient. It's actually just deferred risk. Consent dialogs don't help much either, since users click "Allow" without reading, and that one click grants access that can sit there for years.

Then there's the scope-omission problem, which is quietly one of the worse defaults in the whole ecosystem: some authorization servers, when a client simply doesn't specify a scope parameter, hand back a token with the full permissions of whoever's logged in. No scope requested somehow becomes maximum scope granted. That's not a bug most teams know to look for.

Permission creep finishes the job. Every new feature adds a scope. Almost nobody removes the old ones when a feature gets deprecated, because removing scopes means testing that nothing breaks, and testing takes time nobody budgeted for.

The organizational layer makes this worse, not better. Usually no single team owns the list of what apps hold what access. Employees who authorized some tool three years ago leave the company; their grants don't leave with them. And now every employee with a laptop can connect an AI tool to their email in about four clicks, with zero security review, because nobody asked for permission to grant permissions.

Material Security's 2026 study of 22,332 connected apps puts a number on how fast this is accelerating: 91% of AI and automation apps in the dataset showed up in just the last 16 months, with 325 of 356 first observed since January 2024. More than half of the public, governable apps in that set already hold sensitive or restricted scopes. This isn't a case of a few careless developers. It's an organization-wide absence of anyone minding the store.

The current state of OAuth scope exposure across organizations

Here's the number that should make security teams a little queasy: in that same Material Security dataset, 47.2% of applications (10,545 of them) showed no active usage in the past 90 days. A quarter of the total set, 25.8% (5,752 apps), hadn't been touched in 180 days or more. Their scopes are all still live. Nobody revoked anything just because nobody was using it.

Across the full dataset, 24.5% (5,461 apps) hold at least one active restricted scope, using Google's own classification, not some third-party risk score inflating the number for drama. Narrow that down to public, governable apps, and the share jumps to 53.4% holding sensitive or restricted scopes, with Gmail and Drive access showing up together constantly.

Other data points in the same direction. The 2025 State of SaaS Security Report found 75% of organizations had a SaaS security incident in the past year, up 33% year-over-year, with 41% of security teams pointing to user permission issues and 29% tying incidents directly to misconfigurations. Over in cloud infrastructure, Orca Security found only 55% of the permissions assigned to active AWS IAM roles are ever actually used. OWASP's 2025 Non-Human Identity Top 10 survey found 26% of organizations believe more than half their service accounts are over-privileged. Different systems, same pattern: permissions get handed out generously and collected back rarely.

The AI-app cohort is the newest and least-watched corner of this. Material Security found 149 apps connected for 12 months or more with no review on record, at all, ever. That's not a small oversight. That's a whole category of access nobody's checked since the day it was created.

None of this proves active exploitation, to be clear. The data shows exposure, not necessarily harm already done. But that's exactly why it goes unaddressed: exposure is boring until it isn't, and by the time it isn't, the review that should've happened eighteen months ago obviously didn't.

The technical anti-patterns that turn over-scoped tokens into active attack surface

A few specific design choices turn "we have some old grants lying around" into "someone just read every email in the company."

Scopeless tokens are the sharpest edge here. When a client skips the scope parameter and the server fills in full user permissions by default, there's no containment boundary left. An attacker who steals that token doesn't need to escalate anything. They already have everything.

Coarse-grained scopes are the slower version of the same mistake. Names like users.manage or admin.all are easy to implement and easy to consent to, and that's exactly the problem: one compromised token now carries access far beyond whatever single operation the app actually needed.

Some scopes deserve extra suspicion just because of what they touch. Microsoft 365's MailboxSettings.ReadWrite lets an attacker create mail forwarding rules, which is mailbox takeover without ever needing a password. Google Workspace's gmail.settings.sharing carries a similar risk. Any scope touching money, health records, or admin settings needs fine-grained treatment, full stop, regardless of how much simpler the coarse version would've been to build.

There's also a structural limit worth understanding: OAuth scopes can never exceed what the authorizing user is allowed to do. Which sounds like a safeguard, until you remember admins exist. When an admin consents to a broad-scope app, that app inherits admin-level access, and the scope system offers no extra guardrail there. Scope escalation is a related but distinct flaw, where broken server-side validation lets a client upgrade a token's permissions after the fact, higher than what was originally granted.

All of it gets worse because of one structural fact: tokens outlive the thing that created them. Revoking consent doesn't invalidate tokens already issued. Tokens survive password resets, they survive MFA changes, and in some setups they even survive account disables. A token is tied to the app and the original grant, not to whether the user is currently, actively, logged in and behaving normally.

What exploitation of over-scoped OAuth grants looks like in practice

Midnight Blizzard, the nation-state actor behind Microsoft's January 2024 breach, got in through an OAuth application — an unmonitored non-human identity — that carried broad access. From there they moved laterally into Microsoft's production systems and exfiltrated sensitive data. No password was cracked. No zero-day exploited. Just an over-privileged grant that had been sitting there, unattended.

The Salesloft-Drift breach shows the same pattern at supply-chain scale. An attacker got persistent refresh token access across more than 700 organizations. The breach went undetected long enough to give the attacker ten straight days of active data exfiltration before anyone noticed. Researchers at Obsidian described the blast radius as ten times bigger than comparable direct-compromise incidents. That's the multiplier effect of OAuth exposure sitting inside a shared vendor relationship: one weak link, hundreds of victims.

Then there's the Microsoft 365 consent phishing wave, where fake apps dressed up as Microsoft, Adobe, and DocuSign tricked users into granting access. Close to 3,000 accounts across more than 900 environments got compromised, with the fake apps succeeding in tricking users into granting access roughly 50% of the time. The genuinely absurd detail: clicking "Cancel" triggered the exact same redirect chain as clicking "Allow." The user's intent didn't matter. The trap was already sprung by the time they saw the button.

The same chain logic plays out whenever a vendor compromise cascades through shared OAuth grants. Nothing in such cases is necessarily a flaw in OAuth as a protocol. It is a chain of grants, each reasonable on its own, that adds up to something nobody intended.

Some campaigns don't need a software bug at all — just social engineering aimed at OAuth's device authorization grant, exploited systematically against large enterprises.

And then there's the unglamorous version, which doesn't make headlines but happens constantly: an app called, say, "Campaign Analytics Pro" gets authorized back in 2021 with full Drive read and write access. The employee who approved it leaves. The company behind the app gets acquired, then quietly shut down. The scope grant just sits there, live, attached to nothing, watched by no one.

Every incident above shares the same root. The grants exploited weren't new or exotic. They were old, unreviewed, and over-scoped from the day someone first clicked "Allow."

Designing scopes with minimum access built in from the start

Good scope design starts with naming, which sounds almost too simple to matter, but it's the difference between a consent screen that means something and one that's just noise.

Use a resource.operation pattern: orders:read, orders:write, profile:read, profile:write. Each scope maps to exactly one action on exactly one resource. This makes the scope list self-documenting, and it makes over-requesting visible right there in the consent dialog, instead of hidden behind a vague label. Skip generic top-level names like manage, admin, or all. They're comfortable to build but they hide exactly what's being handed over.

Go fine-grained wherever the operation actually matters. Financial transactions, changes to user data, admin actions, health records: each one earns its own named scope. Coarse scopes are fine for low-stakes, genuinely bundled reads. They're not a shortcut for anything touching real risk.

Never let the scope parameter go unset. Always specify it explicitly, even when the server has a default, because relying on that default hands a security decision to someone else's configuration choice, and you don't know what that choice is.

Request scopes incrementally. Ask only for what the current action needs, and ask for more later, right when the user's flow actually calls for it. This keeps initial grants small and makes any expansion visible and contextual, instead of front-loaded and easy to wave through.

Split read and write into separate scopes for every resource, always, even when there's a temptation to bundle them "in case write access is needed later." That "later" is exactly how coarse scopes get justified in the first place.

For anything high-risk, treat admin consent as its own gate. Document which scopes require admin-level authorization, and enforce that at the server, not just in a wiki page nobody reads. And pair scope design with token lifetime: short-lived access tokens shrink the exploitation window even when a scope ends up broader than you'd like. Narrow scope plus short lifetime is a better bet than either one alone.

Auditing existing OAuth grants to find and close scope exposure already in place

You cannot fix what you haven't counted. Start with inventory, not cleanup.

Pull the full list of authorized OAuth apps across every identity provider in scope, Google Workspace, Microsoft Entra ID, Okta, whatever's in use. For each app, get four things: what scopes it holds, who authorized it, when, and when it was last active. Google Workspace and Microsoft 365 both surface a version of this natively; third-party SaaS security tools exist specifically to stitch this together across platforms when one dashboard isn't enough.

Once you have the list, sort by risk before you touch anything. Tier by scope sensitivity (restricted, sensitive, standard) and by how recently the app's been used. The Material Security numbers give a decent starting threshold: 90 days of no activity earns a review, 180 days earns presumptive revocation unless someone can make a real business case for keeping it. Apps holding admin-level scopes, or anything touching mail settings, Drive, or financial systems, jump to the front of the line regardless of how recently they were used.

Investigate before you revoke; that's the step people skip. Check whether the person who authorized the app still works there. Check whether the vendor is even still in business, since acquired-and-shuttered vendors are an easy, high-priority revocation. Ask the team that owns the integration whether the current scope set is still needed, or whether it's leftover from a feature that got cut two years ago.

Revocation has a mechanical trap built in: revoking consent stops new tokens from being issued, but it does nothing to tokens already handed out. Those need to be explicitly expired or rotated, and that step belongs written into the revocation runbook, not left to memory. And revocation isn't the only lever. Where an integration's genuinely active and needed, work with the vendor or the internal team to re-authorize with a smaller scope set instead of ripping the whole thing out.

AI-connected apps deserve their own dedicated pass here. The average app in that cohort had been running nine months in the Material Security study, and 42% had been connected over a year with, again, essentially no review. This category grew faster than any review process was built to track.

Enforcing minimum scope as an ongoing control, not a one-time cleanup

An audit fixes yesterday's mess. It does nothing to stop tomorrow's from piling up the exact same way, which is the part most companies skip past.

Set policy before any new OAuth app goes live in production, not nine months after. Require scope disclosure and a security review up front, as a gate, not a suggestion buried in onboarding paperwork someone will "get to eventually."

Build or buy detection for a couple of specific signals. Flag every new app authorization event, especially ones requesting restricted or sensitive scopes, so nothing quietly slips through unnoticed. And flag admin users authorizing any OAuth app specifically, since those grants inherit elevated permissions automatically and deserve a different, louder alert than a regular employee clicking "Allow" on a scheduling tool.

Minimum scope isn't a task you finish. It's a habit you keep, the same way you keep locking the door even after nobody's broken in yet.

Sources

  1. obsidiansecurity.com
  2. appomni.com
  3. dl.acm.org

More in Auth and Security