AADSTS70011 - Invalid Scope
Azure AADSTS70011 is a request-shape failure indicating that the `scope` parameter in the authentication request is malformed, misspelled, or contains scopes from multiple unrelated resources in a single token request.
Last reviewed: April 7, 2026|Source-backed guidance under our editorial policy
Start Here
Use the closest compare guide, playbook, or adjacent error page to narrow the decision faster before you start changing production systems.
This page is part of the Error Reference library. Learn more about the project or report a correction.
What Does Invalid Scope Mean?
AADSTS70011 is a semantic mismatch. Under OAuth 2.0 and OpenID Connect, a single access token is generally issued for a single resource or audience. If the application requests User.Read for Microsoft Graph and api://my-custom-api/access for a custom API in the same token request, Entra ID returns AADSTS70011. It also appears when the wrong scope type is used for the selected flow, such as requesting a delegated scope in a daemon-style client-credentials flow.
Common Causes
- -Multi-Resource Scope Mix: Combining Microsoft Graph scopes with custom API scopes in one request string.
- -Spelling Errors: Typographical mistakes such as
Directory.Read.Alllor invalid permission names. - -Malformed `/.default` Usage: Static scope requests are formatted incorrectly, for example by omitting the resource prefix or misusing
/.defaultin the wrong flow. - -Flow And Scope Mismatch: Delegated permissions are requested during a client-credentials flow, or application-style
/.defaultis used where a delegated user scope is expected. - -Invalid Separators: Scopes are separated with commas or semicolons instead of spaces in the raw request.
How to Fix Invalid Scope
- 1Split The Requests: If you need tokens for Microsoft Graph and a custom API, make two separate token requests.
- 2Check The Resource Prefix: Ensure custom scopes are fully qualified, for example
api://{client-id}/scope_name. - 3Use `/.default` For Daemons: If the app is a background service using client credentials, request
https://graph.microsoft.com/.defaultinstead of delegated scope names. - 4Validate In The Portal: In App Registration > Expose an API, copy the scope URI exactly as configured rather than rebuilding it manually.
Step-by-Step Diagnosis for Invalid Scope
- 1Inspect the network trace or debugger and look directly at the
scopeparameter in the authorize or token request. - 2Count the resources referenced in the scope list. If more than one base resource or App ID URI appears, that is usually the root cause.
- 3Verify the OAuth flow type and match the scope style to that flow: delegated for interactive user flows,
/.defaultfor client credentials. - 4Check for invisible characters, bad URL encoding, or incorrect separators in the scope string.
AADSTS70011 vs AADSTS65001
- -AADSTS70011: The scope request itself is structurally or semantically invalid.
- -AADSTS65001: The scope is meaningful, but consent is missing for it.
The Single Resource Rule
- -An access token is usually a key for one specific door. You cannot request a single token that simultaneously targets Microsoft Graph and your custom backend API.
Implementation Examples
// Incorrect: mixing Microsoft Graph and custom API scopes
const request = { scopes: ["User.Read", "api://my-backend/access"] };
// Correct: get a Graph token first
const graphResponse = await msalInstance.acquireTokenSilent({ scopes: ["User.Read"] });
// Then request a token for your API separately
const apiResponse = await msalInstance.acquireTokenSilent({ scopes: ["api://my-backend/access"] });# Use /.default to request all pre-configured application permissions
curl -X POST "https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token" \
-d "client_id={id}" \
-d "scope=https://graph.microsoft.com/.default" \
-d "grant_type=client_credentials" \
-d "client_secret={secret}"Seen in Production
One token requested for Graph and a custom API at the same time
Frequency: high
Example: A developer tries to get one token that can read a user’s mail and call their own backend API in a single request. Entra returns AADSTS70011 because the request crosses resource boundaries.
Fix: Acquire separate tokens. One for Graph and one for the custom API.
Typo in `/.default` breaks daemon auth
Frequency: common
Example: A script requests https://graph.microsoft.com/default without the dot. The token request fails with AADSTS70011.
Fix: Correct the value to https://graph.microsoft.com/.default.
Debugging Tools
- -Fiddler or Network Trace: Best way to inspect the raw
scopestring sent in the request body or query. - -Entra ID Portal Expose an API View: Useful for verifying the exact URI of custom scopes.
- -Jwt.ms: Helpful for checking whether a returned token, when successful, matches the audience and scopes you expected.
How to Verify the Fix
- -Confirm the application now makes distinct token requests for each unique resource.
- -Verify the token response contains the expected
scporrolesclaims for the corrected request. - -Ensure the
audclaim in the resulting JWT matches the intended resource.
How to Prevent Recurrence
- -Centralize Scope Constants: Keep Graph scopes and custom API scopes in separate configuration arrays.
- -Use SDK Best Practices: Let MSAL manage formatting, but never pass a mixed-resource scope array into a single request.
- -Add CI Validation: Include tests that validate scope structure and flow compatibility before deployment.
- -Pro tip: If AADSTS70011 appears right after migrating from ADAL to MSAL, inspect how old resource parameters were converted into scope strings. This is a very common migration pitfall.
Official References
Provider Context
This guidance is specific to Azure services. Always validate implementation details against official provider documentation before deploying to production.