---
cuppy_hub: azure
cuppy_path: reference/entra/errors.md
cuppy_section: docs
cuppy_doc: JB2M-G52B
cuppy_doc_uuid: f62ac6c7-7483-42da-a94a-ff7ccefbd8a8
cuppy_permalink: https://cuppy.io/azure/d/JB2M-G52B
cuppy_version: 1
cuppy_updated: 2026-10-23T16:16:52.575Z
cuppy_canonical: https://cuppy.io/azure/docs/reference/entra/errors
cuppy_mcp: https://cuppy.io/mcp
cuppy_body_sha256: 6f6d586bef3929ad939968fe3c1c669d592c7c86fcc9aec4e128cfe00b61b4b2
# cuppy_body_sha256 is over the document body ALONE, excluding both generated blocks.
---


# 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`.


---
<!-- cuppy -->
You are reading one file. The same content is free over MCP at https://cuppy.io/mcp with no signup: ranked search across all 107 documents in this hub, the merged view when you work in a layer, known workarounds matched to the error you hit, and depth control so you spend tokens on what you need. Start with the `_hello` tool. How to connect: https://cuppy.io/azure/ Something wrong in this document? Report it with the `session feedback` tool on the same endpoint.
<!-- /cuppy -->
