User.ReadBasic.All loses access to app roles and license data this month
User.ReadBasic.All has quietly exposed app role assignments and license details since it shipped. That access closes in a rollout completing late September 2026. What breaks, and one discrepancy in Microsoft's own migration guidance worth checking before you act on it.
If an app in your tenant holds only User.ReadBasic.All and reads a user’s app role assignments or license details, that call stops working this month. Microsoft is closing a permission scope that never should have covered that data.
Key Takeaways
User.ReadBasic.Allhas quietly allowed reading app role assignments and license details, alongside its intended basic profile fields. Microsoft is closing that gap (MC1470871)- Rollout runs mid- through late September 2026, worldwide. No action needed if your app only reads basic profile fields
- Microsoft’s migration guidance recommends
User.Read.All. The official endpoint documentation lists a different permission entirely, test the actual call before you grant anything- Affected calls:
GET /users/{id}/appRoleAssignments(incl.Get-MgUserAppRoleAssignment) and license-detail reads
What changes, and when
| Before the rollout | After the rollout completes | |
|---|---|---|
| Basic profile fields (name, email, photo) | Readable with User.ReadBasic.All | Unchanged |
| App role assignments | Readable with User.ReadBasic.All alone | No longer readable with this permission |
| License details | Readable with User.ReadBasic.All alone | No longer readable with this permission |
| Scope | N/A | Worldwide, mid- to late September 2026 |
The permission itself isn’t deprecated. It just stops returning data it was never supposed to return (Microsoft Graph permissions reference never listed app role assignments or license info in its scope).
One thing worth checking before you grant anything: Microsoft’s MC1470871 guidance recommends User.Read.All for app role assignments, but Microsoft’s own endpoint documentation lists AppRoleAssignment.ReadWrite.All or Directory.Read.All instead, User.Read.All doesn’t appear there at all. Two Microsoft-owned pages, two different answers. Test the actual call against a non-production app registration before rolling out broadly.
Check this before the rollout completes
- Check every app registration holding
User.ReadBasic.All: does its code callGET /users/{id}/appRoleAssignmentsor read license details? If not, you’re unaffected - If either shows up, grant the confirmed replacement permission alongside (not instead of)
User.ReadBasic.All, get fresh admin consent, and test the specific call before the rollout reaches your tenant - Custom onboarding tools, license-reporting dashboards, and internal HR integrations are the most common place this shows up
Check it automatically
Get-ReadBasicAllExposureReport.ps1 inventories every app holding User.ReadBasic.All and flags whether it already also holds User.Read.All or LicenseAssignment.Read.All. It can’t see what an app’s code actually calls (Graph doesn’t log that), so it’s a starting list for review, not a verdict.
Frequently asked questions
I only use User.ReadBasic.All for a user’s name and photo. Do I need to do anything? No, that’s exactly its intended scope and it’s unaffected.
Is this a breaking change or a security fix? Both. For apps relying on the unintended access, a breaking change needing a permissions update. For everyone else, a quiet fix bringing the permission back to its documented scope.