Authentication_MSGraphPermissionMissing: Graph names the permission you need
Short answer: Authentication_MSGraphPermissionMissing means your app called a Microsoft Graph endpoint without a permission that endpoint requires, and unlike the other 403 codes, the message names the permission. It is the most useful of Graph's three permission-denied codes because the fix is written into the response.
Fix: Read the permission name out of the message, add it to the app registration under API permissions, and grant admin consent. Then acquire a new token: a token issued before the grant does not carry the new role, so the call keeps failing until you request a fresh one. Full steps
| Error code | Authentication_MSGraphPermissionMissing |
|---|---|
| HTTP status | 403 |
| In Microsoft's Graph error documentation | No (checked ). The wording on this page is what Graph returned in the lab. |
| Category | Graph permissions |
| Attack signal | Medium: worth a look in context |
What does Authentication_MSGraphPermissionMissing mean?
Section titled “What does Authentication_MSGraphPermissionMissing mean?”Your app’s token was valid. Microsoft Graph accepted it, looked at the permissions inside it, and found that none of them is one this endpoint will accept. The response is HTTP 403, and the message names the permission.
That last part is why this code is worth knowing by name. Graph has three different 403 codes for “you do not have permission”, and this is the only one that tells you what to grant:
| Code | What the message gives you |
|---|---|
Authentication_MSGraphPermissionMissing |
The permission name, in the message |
AccessDenied |
“required scopes are missing in the token” |
Authorization_RequestDenied |
“Insufficient privileges to complete the operation.” |
No Microsoft page defines this code. A search of learn.microsoft.com for the literal string "Authentication_MSGraphPermissionMissing", with and without a site restriction, returned no page containing it; one result that looked like a hit — Microsoft’s Resolve Microsoft Graph authorization errors page — was fetched in two locales and contains the string in neither, so the search index appears to be matching it loosely rather than literally. Microsoft’s current Graph error reference lists HTTP status codes only and has no named-code table. The wording on this page is what Graph v1.0 returned in a lab tenant on 31 October 2026.
So if you are writing an error handler that has to produce something an operator can act on, this code is the easy case: pass the message through. For the other two you have to look up the endpoint’s required permission yourself.
Reproduced in the lab
Section titled “Reproduced in the lab”On 31 October 2026 an automated run called GET /auditLogs/signIns?$top=1 with an app-only token whose roles claim, recorded by the run, held Application.ReadWrite.OwnedBy and User.ReadWrite.All and no audit-log permission. The response was HTTP 403:
{ "error": { "code": "Authentication_MSGraphPermissionMissing", "message": "The principal does not have any one of the required Microsoft Graph permissions: AuditLog.Read.All to call this API. For more information about Microsoft Graph permissions, please visit https://learn.microsoft.com/graph/permissions-overview." }}The same call to /auditLogs/directoryAudits returned the same code naming the same permission, and the same call against https://graph.microsoft.com/beta returned the same code and the same message. That is one endpoint on beta, not a general claim about beta.
One error can hide another. The lab tenant runs Entra ID Free, which cannot serve sign-in logs through Graph at all; that limit has its own error code, Authentication_RequestFromNonPremiumTenantOrB2CTenant. The run never saw it. Our reading is that the permission check runs before the licence check, so the licence limit was never reached — the run cannot confirm an ordering, because only one error came back, and the tenant’s licence tier is site knowledge rather than something the run recorded. If you are on a Free or B2C tenant and you fix the permission, it is worth expecting a second, different 403 behind it.
Is it an attack signal?
Section titled “Is it an attack signal?”Medium, and only in aggregate.
A single occurrence is almost always a new integration whose permissions were never consented, or a script written against documentation for a different endpoint. That is the normal case and it is noisy.
What is worth an alert is one service principal producing this code across many different endpoints in a short window. That is the shape of an app enumerating what it can reach: call everything, keep what returns 200. The message text makes it efficient for whoever is doing it, because each failure names the permission they would need. If a non-interactive identity in your tenant is walking /auditLogs, /policies, /directoryRoles and /identity and collecting 403s, that is reconnaissance against your tenant’s permission model, whatever the intent behind it.
You will not find these in the Entra sign-in logs — a rejected Graph call writes no sign-in row. The service principal’s token acquisition does appear, in AADServicePrincipalSignInLogs, but it succeeded, so it looks like any other successful sign-in. The calls themselves land in MicrosoftGraphActivityLogs: KQL for finding this pattern. That table records the HTTP status and not the error code, so you hunt 403s by endpoint rather than by this code.
How do I fix it?
Section titled “How do I fix it?”- Take the permission name out of the message. It is the string after “required Microsoft Graph permissions:”. If several are listed, any one of them is enough — the message says “any one of the required”.
- Add it to the right app. In the Microsoft Entra admin center: Identity > Applications > App registrations > your app > API permissions > Add a permission > Microsoft Graph. Choose Application permissions for an app-only (client credentials) token, Delegated permissions for one acquired on behalf of a signed-in user. Getting this pair wrong is the commonest reason the error survives the fix.
- Grant admin consent. Application permissions do nothing until an administrator consents to them. The button is Grant admin consent for <tenant> on the same blade.
- Acquire a new token. This is the step most often missed. Permissions live inside the token as roles; a token issued before the consent does not contain the new one and will keep failing until it expires. Clear your token cache or restart the process.
- If it still fails, look for a second cause behind the first. As above, a licence limit or a tenant-level restriction can be waiting behind the permission check.
Before you grant it, check the permission is the one you actually need. AuditLog.Read.All lets an app read every sign-in and every directory change in the tenant. Check the permissions reference for the endpoint you are calling: it lists permissions least-privileged first, and for several endpoints the least-privileged option is much narrower than the one the error names. For /auditLogs/signIns with an app-only token there is no narrower alternative, so this one is all or nothing. A permission granted to make one call work is standing privilege for as long as the app exists.
Related
Section titled “Related”AccessDenied— the same class of failure, without the permission nameAuthorization_RequestDenied— the directory’s own permission denialInvalidAuthenticationToken— the token itself was rejected, before permissions were checked- All Graph error codes