Microsoft Entra token errors for apps and service principals (AADSTS)
Look up an AADSTS error from a token request made by an app, a service principal or a script — tenant or app not found, missing service principal, bad or expired secret or certificate, wrong scope or resource, consent and admin consent, multitenant and /common errors — each with the cause, the check that confirms it, and the fix. User sign-in and federated-credential errors have their own catalogues.
markdownreferencev1JB2M-G52Bstage: operatetrust: officialtrust: fieldservice: entrainterface: anyAADSTSAADSTS700016AADSTS90002AADSTS50194AADSTS7000215AADSTS7000222AADSTS7000218AADSTS70002AADSTS700027AADSTS7000112AADSTS500014AADSTS500011AADSTS50001AADSTS70011AADSTS650057AADSTS650056AADSTS65001AADSTS90094AADSTS90009AADSTS50011AADSTS900144AADSTS9002313invalid_clientinvalid_scopeunauthorized_clientinvalid_resourceclient secret expiredapplication not found in the directory.default scopeadmin consent required
Microsoft Entra token errors for apps and service principals
An AADSTS error comes from the token request, before any Azure service sees your call. Fix it here, not in the service. The response JSON carries error (an OAuth class such as invalid_client), error_description (starts with AADSTS<n>:), error_codes, trace_id, correlation_id and error_uri. Branch code on error or error_codes, never on the description text: Microsoft says the wording changes. The live description of any code is at https://login.microsoftonline.com/error?code=<n>.
In the Azure SDK for JavaScript, these arrive as AuthenticationRequiredError or AuthenticationError with the AADSTS line inside the message (reference/azure-identity/errors.md).
Two checks used below:
- App lookup:
az ad app show --id <client-id> --query "{appId:appId, audience:signInAudience}", run while signed in to the tenant in the request (az login --tenant <tenant-id>). - SP lookup:
az ad sp show --id <client-id> --query "{enabled:accountEnabled, tenant:appOwnerOrganizationId}"in the same tenant.
Tenant, app and service principal
| Code | Cause → fix | Check |
|---|---|---|
AADSTS90002 InvalidTenantName | The tenant in the URL wasn't found. Check the tenant ID; prefer the GUID to a domain name | curl -s https://login.microsoftonline.com/<tenant>/v2.0/.well-known/openid-configuration returns an error |
AADSTS700016 UnauthorizedClient_DoesNotMatchRequest | No app with this client ID in this tenant: wrong client ID or wrong tenant, or a multitenant app with no service principal here yet (needs consent by that tenant's admin) | SP lookup in the requesting tenant returns nothing |
AADSTS7000112 UnauthorizedClientApplicationDisabled | The app's service principal is disabled | SP lookup → enabled: false |
AADSTS500014 | The resource's service principal is disabled (a lapsed subscription or an admin disabled it) | az ad sp show --id <resource-app-id> → accountEnabled |
AADSTS500011 InvalidResourceServicePrincipalNotFound | The resource (API) has no service principal in this tenant: wrong resource URI, or a third-party API nobody has consented to here | az ad sp show --id <resource-app-id-or-uri> returns nothing |
AADSTS50194 | A single-tenant app called /common. Use https://login.microsoftonline.com/<tenant-id>/…, or make the app multitenant | App lookup → audience: AzureADMyOrg |
AADSTS90009 | The app asked for a token for itself by its URI. Use its GUID app ID as the resource | Compare the scope's resource with the client ID |
Created with az ad app create, then nothing works? Registering in the portal creates the app object and its service principal; creating through Microsoft Graph, which the CLI uses, creates only the app. Run az ad sp create --id <client-id>. (az ad sp create-for-rbac creates both, plus a one-year secret, and assigns no role unless you pass --role and --scopes.)
Credentials
| Code | Cause → fix | Check |
|---|---|---|
AADSTS7000215 | Invalid client secret. The message itself says to send the secret's value, not its ID; field sources name that mix-up as the usual cause. Otherwise the secret was deleted or belongs to another app | az ad app credential list --id <client-id> → is there a keyId you recognise? The value can't be read back: create a new secret |
AADSTS7000222 InvalidClientSecretExpiredKeysProvided | The secret expired. Create a new one, or switch to a certificate or a federated credential | Same call → endDateTime in the past |
AADSTS70002 InvalidClient | The client_secret doesn't match the expected value for this client | Confirm the client ID and the secret come from the same app registration |
AADSTS7000218 | The request body has no client_secret or client_assertion: the app is a confidential client and no credential was sent (in scripts, typically an unset variable: the hub's reading) | Print which of AZURE_CLIENT_SECRET, AZURE_CLIENT_CERTIFICATE_PATH is set (not its value) |
AADSTS700027 | Client assertion failed signature validation: the certificate used to sign isn't one uploaded to the app, or the wrong private key | az ad app credential list --id <client-id> --cert → compare thumbprints with your certificate |
AADSTS900144 | A required parameter is missing from the body (grant_type, client_id, scope). The message names it | Log the form body keys (not values) |
AADSTS9002313 InvalidRequest | Malformed request to the endpoint. Microsoft suggests capturing the request (a Fiddler trace); the token endpoint takes an application/x-www-form-urlencoded body | The captured request's body and Content-Type |
Scope, resource and consent
| Code | Cause → fix | Check |
|---|---|---|
AADSTS70011 InvalidScope | Bad scope. App-only (client credentials) tokens need <resource>/.default, for one resource per request: https://management.azure.com/.default, https://vault.azure.net/.default, https://graph.microsoft.com/.default | The scope value in the request |
AADSTS50001 InvalidResource | The resource URI doesn't exist or is disabled (typo, wrong cloud) | az ad sp show --id <resource-uri> |
AADSTS650057 | The app requested a resource that isn't in its API permissions (required resource access) | az ad app permission list --id <client-id> |
AADSTS650056 | Misconfigured app: no permissions listed for that resource, or admin consent missing for them | Same call, then az ad app permission list-grants --id <client-id> --show-resource-name |
AADSTS65001 DelegationDoesNotExist | No consent for this app and resource. Interactive users can consent; for daemons, an admin grants the application permissions | az ad app permission list-grants --id <client-id> --show-resource-name |
AADSTS90094 AdminConsentRequired | The permissions requested need an administrator. Ask one to run az ad app permission admin-consent --id <client-id> or use the admin consent endpoint | Same call shows no grant |
AADSTS50011 InvalidReplyTo | The redirect URI sent is missing from, or doesn't match, the app's registered reply addresses. Add the exact URI | az ad app show --id <client-id> --query "{web:web.redirectUris, spa:spa.redirectUris, public:publicClient.redirectUris}" |
App permissions vs delegated: a token for an app with no user carries a roles claim (application permissions, granted by an admin); scp appears only in user tokens. A daemon that was given only delegated permissions gets a token with no roles, so the failure shows up at the API (401 or 403), not as an AADSTS error (the hub's reading).
When none of these fits
Search the code at https://login.microsoftonline.com/error?code=<n>, check that the client ID, tenant ID and credential all come from the same app registration, and keep the trace_id and correlation_id from the response for support. A user-interactive failure (MFA, conditional access, password) is in reference/entra/sign-in-errors.md; a federated credential failure (AADSTS70021, AADSTS7002xx) is in reference/entra/federated-credential-errors.md.