OAuth Scope Expansion Breaking Existing Integrations
Scope changes break integrations silently, leaving developers guessing at the real problem.
OAuth scopes are the permission strings that govern what an access token can actually do, and they sit at the center of nearly every modern API integration. When that scope set changes, whether a provider deprecates a scope outright, an app requests additional permissions, a token gets reissued with fewer scopes than before, or a restructuring replaces broad strings with granular ones, integrations break in ways that are rarely obvious at the surface. The failure might show up as a 401, a silent data feed that stops filling in, an automation that goes dark with no error attached, or a confusing situation where a user's SSO login succeeds but every API call behind it fails.
Understanding how each of those failure modes actually works, what's mechanically happening inside the token lifecycle, and why the symptoms so rarely point directly at the scope layer, is the foundation for diagnosing and preventing them. This post works through the full picture: the four mechanisms that change a scope set mid-integration, why broken integrations rarely announce themselves clearly, how over-scoped tokens become breach vectors, what OAuth 2.1 is about to break in production, and what both developers and providers can do to manage scope changes without taking downstream integrations down with them.
What OAuth scopes control
Scopes are permission strings glued to an access token, and the API checks them on every single call before deciding what the caller gets to do. That's the whole mechanism. Nothing fancier than a bouncer checking a wristband color at the door, except the wristband is a string like calendar.readonly and the bouncer is a line of validation code that runs thousands of times a second.
The consent screen is where this gets translated into something a human can understand. "Read your email." "Manage your calendar." Those friendly little checkboxes map directly to technical scope strings, anf d the authorization server validates the request against them every time. So when someone clicks "Allow," they're not agreeing to a vibe. They're authorizing a specific string, forever, until somebody actively goes and revokes it.
That "forever" part is most people skip past. Granted scopes don't expire on their own. They don't get cleaned up when a password changes, when MFA gets turned on, or when an employee walks out the door for the last time. The token doesn't know any of that happened. It just keeps working, quietly, in the background, holding whatever permissions it was handed on day one.
Most companies treat that initial "Allow" click as a closed chapter. Authorized once, filed away, never looked at again. Obsidian Security's research (updated September 24, 2026) found scopes granted years ago are still sitting there as live attack surface, because nobody ever goes back to check. That's the real boundary problem: scopes aren't a one-time decision; they're a standing capability that persists until somebody actively kills it. Once that framing clicks, it becomes obvious why any change to a scope set, tightening it, expanding it, reissuing it, ends up breaking something. Every integration downstream was built on the assumption that the boundary would just stay put.
The four mechanisms that change a scope set mid-integration
Four things can move that boundary out from under an integration, and they don't look or feel alike at all. Knowing which one you're dealing with is most of the diagnostic work, honestly.
The first is provider-side deprecation: the company running the API just retires a scope string outright, and any token still carrying it either stops working or starts throwing errors. MYOB did exactly this with its legacy CompanyFile scope, deprecating it in March 2025 and cutting it off for all keys as of September 1, 2026, giving every integration built on the old scope a hard deadline to migrate MYOB OAuth2.0 Scope Changes. Figma ran a similar play with files:read in September 2025 MYOB OAuth2.0 Scope Changes. Supabase's OAuth integration kept appending that scope to its authorization URLs, the scope stopped being valid, and submission flows broke even while Figma's own grace period was supposedly still active MYOB OAuth2.0 Scope Changes. Grace periods help, in theory. They don't help if your code never checks whether the grace period actually applies to you.
The second mechanism is restructuring, which is sneakier because the old scope doesn't necessarily die, it just gets replaced by a pile of smaller ones. Xero swapped two broad OAuth scopes for ten granular ones, effective for any app created after March 2, 2026, with existing apps given until September 13, 2027 to catch up. By the end of April 2026, Xero had already assigned the new granular scopes to every existing app inside its developer portal. Sounds like the migration handled itself. It didn't handle itself. None of that propagated automatically to tokens already in use, so developers still had to go update authorization URLs and drag users back through consent. The scopes existed on paper. The tokens never got the memo.
Third: app-side expansion, which is really just an integration asking for more over time. A vendor starts with read access, later decides it wants write access too, and fires off a new consent screen. Users click through it. Mostly they don't stop to ask why a tool that used to just read their calendar now wants to send emails as them. That's a design feature of incremental authorization getting used exactly as designed, just maybe not the way anyone imagined.
Fourth, and probably the sneakiest: token reissuance that drops scopes nobody meant to drop. A refresh cycle runs, a new token comes back, and it's missing permissions the old token had. The league/oauth2-client library shipped a change in version 2.8.0, back in December 2024, that broke refresh token handling. Labeled a minor point release, by the way, which is the software equivalent of a landmine with a "watch your step" sticker on it that nobody reads. Refresh token rotation makes this worse in general: Microsoft Entra ID, for one, issues a brand new refresh token on every single refresh request and invalidates the old one, so if that rotation ever fails partway through, the whole chain silently snaps.
There's a fifth wrinkle too, and it's not technically a scope change but it gets mistaken for one constantly. SSO federation lets a user log in through the corporate identity provider just fine, but the OAuth grant itself is missing, revoked, or blocked by some admin policy nobody told the user about. Login succeeds. The integration fails anyway. Access tokens carry OAuth 2.0 scopes, which are permission strings the API reads on every call to decide what the caller may do.
Why broken integrations rarely announce themselves clearly
None of this arrives with a helpful label. A 401, a 403, a data feed that just quietly stops filling in, or an automation that goes dark with zero error message attached appears instead. Not one of those symptoms says "scope problem" on the tin.
The SSO trap is the clearest version of this. A user authenticates fine, sails right through the identity provider, and then every single API call fails anyway. Support tickets on this almost always get logged as an integration bug or a permissions glitch. Rarely does anyone write "OAuth scope issue" as the first guess, because from where the user sits, login worked. Why would anything be wrong? Three separate layers have to hold up independently here: authentication (who is this), delegated authorization (what is this app allowed to do), and application entitlement (are those scopes even approved inside this particular workspace). Any one of the three can snap while the other two look perfectly healthy.
HubSpot access tokens expire in 30 minutes Nango Blog. Salesforce tokens run much longer but an admin can kill one at will, at any moment Nango Blog. Notion doesn't even call them scopes. It calls them "capabilities," sets them at registration, and drops the scope parameter entirely, so standard OAuth debugging tools produce results that just don't line up with what you're looking at. Nango looked across 50 popular APIs and found every single one implements a different slice of the OAuth standard, with its own quirks and nonstandard parameters and error behavior Nango Blog. So the fix that worked last week on Salesforce tells you nothing about the bug in front of you on HubSpot Nango Blog.
A ticket that reads something like: "SSO works fine, but the integration is broken" eventually reveals all of this." That single sentence is usually the tip of a scope mismatch that's been sitting there quietly since the day the thing was first authorized. Worse still are the orphaned grants: apps authorized by an employee who left the company years ago, or by a vendor that got acquired and quietly shut down. Those grants stay active with nobody watching, sometimes for years, until behavior changes and there's no owner left to notice.
The security cost of scope drift: how over-scoped tokens become breach vectors
Scope drift doesn't stay an annoyance; it becomes an actual breach mechanism. The attack pattern is almost boringly simple once you see it laid out: compromise a third-party SaaS vendor, dig through its stored OAuth tokens, find the ones connecting that vendor to its downstream customers, and just use them. No suspicious login. No stolen password. No shady domain lighting up a security dashboard somewhere. Just a token doing what it was authorized to do, for the wrong person.
This isn't hypothetical. ShinyHunters stole Drift OAuth tokens from Salesloft and used them to reach into 760 separate Salesforce environments. Tokens tied to Anodot got used to breach Snowflake environments, Rockstar Games among them. And at Vercel, tokens from a deprecated AI app quietly exposed the company's Google Workspace. Widening the lens shows the pattern keeps repeating: Salesloft Drift and Gainsight in 2025, then Context.ai, Anodot, and Klue in 2026, each one dragging hundreds of downstream victims along with it.
The Klue incident's timeline is so tight it's worth walking through. Anomalous activity got flagged on June 12, 2026. Anomalous activity was detected on 12 June 2026, and by 13 June 2026 OAuth credentials were deactivated for all customers. Integrations across Salesforce, HubSpot, SharePoint, Zoom, Gong, Chorus, Clari, Google Drive, and Slack all got shut off temporarily. Huntress, Recorded Future, Tanium, and Jamf were among the named organizations caught up in it. The group behind it, tracked as Icarus, got in through a compromised legacy credential tied to an integration tool. Not an OAuth flaw. A forgotten door left unlocked. One over-scoped, long-lived integration was all it took once one link in the vendor chain gave way.
Vercel's case tells nearly the same story from the other direction. An employee tried out Context.ai, connected it to Google Workspace, and moved on with life, the way people do with free trials. Nobody revoked it. When Context.ai got breached, that forgotten little connection turned out to be the open door. Multiply that by the fact that Push Security's data shows organizations run an average of 17 unique AI app integrations across Microsoft 365 and Google Workspace alone, and most of those got authorized by individual employees with nobody's approval involved Nango Blog. That's not a handful of loose ends. That's a whole junk drawer of live credentials nobody's inventoried.
Standard incident response doesn't touch any of this, either. Reset the password, roll out MFA, offboard the employee, all standard moves, and none of them cancel an OAuth grant. The token just keeps working. And this isn't only a security headache, it's a compliance one: excessive OAuth scope runs directly against the least-privilege requirements baked into ISO 27001, SOC 2, and DORA Push Security. That's a control failure sitting on an audit report, not a footnote Push Security. NHI Mgmt Group's June 2026 figures found that 97% of non-human identities carry more privilege than they need. Scope sprawl isn't the exception here, it's the baseline.
OAuth 2.1 as a structural source of coming scope breakage
OAuth 2.1 is meant to tidy up years of scattered best practices from 2.0 into one tighter spec. As of March 2026, the draft (IETF draft-ietf-oauth-v2-1-15) is still technically an Internet Draft, yet it's stable enough that major identity providers are already building to it. Okta, Microsoft Entra ID, and Auth0 are all implementing its requirements ahead of the thing even being finalized. Which means the ground is shifting under integrations before the spec has technically stopped moving.
Of the changes coming, a handful will actually break things already in production. The implicit flow is gone, full stop, so any single-page app or mobile app still leaning on it has to migrate over to authorization code flow with PKCE. The Resource Owner Password Credentials flow is gone too, so anything passing a username and password straight through breaks. Redirect URI matching gets strict, so the partial matches and wildcard patterns that quietly worked under 2.0 will now get flatly rejected.
There's a genuine upgrade buried in here too, not just teardown. Rich Authorization Requests let 2.1 express permission with actual precision, something like "allow this transaction up to $500 from account X," instead of a blunt scope string that can't capture a limit like that. Financial services and healthcare, where a plain string is too coarse to describe what's actually being allowed, stand to benefit the most from that shift.
None of these breaks require a provider to touch a single scope string. The grant type changes and flow changes hit existing code on their own terms, regardless of how scopes are configured. Library maintainers can ship 2.1 compliance in a routine point release rather than a major version bump, and the minor-release trap shows up here exactly like it did with league/oauth2-client 2.8.0, sliding straight past anyone only skimming changelogs for the big stuff.
How to diagnose scope breakage systematically rather than by accident
Start with the three-layer split every time, no exceptions. Confirm authentication actually succeeded, then check whether delegated authorization exists for the scopes the call needs, then verify the app is actually entitled to use those scopes in that specific target environment.
Go check the authorization URL before anything else. Is it still requesting the current, correct scope strings? Restructures like Xero's ten-for-two swap are the trap here specifically because they leave the existing token untouched. The URL goes stale, but nothing breaks yet, right up until the next re-authorization or token refresh forces the mismatch into the open. By the time someone notices, the root cause is weeks old.
Read the provider's changelog before combing through your own logs. MYOB announced its deprecation in March 2025 and didn't enforce it until September 2026 MYOB OAuth2.0 Scope Changes. That gap between the announcement and the enforcement date is the window where diagnosis is actually easy, because the answer is sitting in a blog post instead of buried in a stack trace.
For anything SSO-adjacent, separate the identity layer from the OAuth layer before doing anything else. A scope change is a breaking change for every integration that depends on it, because a user logging in through the corporate IdP successfully proves absolutely nothing about whether the OAuth grant underneath is still valid. Check admin consent state and domain-wide delegation settings as their own distinct checkpoints.
For token reissuance problems, compare the new token's scope set against the original's, line by line if you have to, especially with providers that don't return an expires_in field or that silently trim scopes during rotation. And check library changelogs with the same care given to provider changelogs. The league/oauth2-client 2.8.0 case is the textbook example: a routine, boring-sounding point release that quietly broke refresh token handling for anyone who wasn't paying attention.
What providers should build into scope changes to avoid breaking integrations downstream
A scope change is a breaking change for every integration that depends on it, full stop, even though providers keep acting like it isn't true. Scope changes deserve the exact same treatment, because the downstream damage is identical, tokens stop working, calls start failing, and someone's automation goes dark at 2 a.m. with no explanation attached.
That means treating a scope deprecation like MYOB's, announced well ahead of enforcement, as the standard rather than the exception MYOB OAuth2.0 Scope Changes. It means never assuming a portal-side scope assignment (the way Xero handled its granular rollout) will magically reach existing tokens on its own, because it won't, and telling developers exactly that up front saves everyone a debugging session later. It means documenting refresh token rotation behavior in plain language instead of leaving developers to discover it the hard way when a chain silently drops. None of this is complicated engineering. It's discipline, applied consistently, to a part of the system everyone quietly agreed to stop watching the moment the first consent screen got clicked through.
Sources
- OAuth Scopes: Permissions & Security Best Practices
- Malicious OAuth integrations: how to detect, block, and remediate them | Push Security
- Why is OAuth still hard in 2026? | Nango Blog
- MYOB OAuth2.0 Scope Changes – Support for the MYOB family of SME product APIs
- supabase figma oauth broken files read incorrect app scope 45602
- The 2026 SaaS Breach Crisis: OAuth Abuse, Token Theft & ShinyHunters
- Vercel Security Breach April 2026: OAuth Attack Explained
- 6 OAuth 2.1 Changes That Will Break (and Fix) Your B2B Authentication Stack | SSOJet - Enterprise SSO & Identity Solutions



