AADSTS7000215: Invalid client secret provided. Ensure the secret being sent
in the request is the client secret value, not the client secret ID,
for a secret added to app '<your-app-id>'.
If that is your situation, there is a very good chance you pasted the Secret ID
instead of the secret's Value. It is the single most common cause of this error
— common enough that Microsoft wrote it into the error message itself, and
people still miss it, because under pressure nobody reads past “Invalid client
secret”. This guide covers the quick check, every other cause worth knowing,
and how 7000215 differs from its sibling,
AADSTS7000222.
1a2b3c4d-5e6f-... — that is the Secret ID,
not the secret. The real Value is a longer random string (it often contains
~), and it was shown exactly once, when the secret was created. You
cannot retrieve it again: create a new secret, copy the Value column this
time, and update your config.
What AADSTS7000215 actually means
AADSTS7000215 is Microsoft Entra ID (formerly Azure AD) rejecting a token
request with invalid_client, because the secret string your application
presented does not match any active client secret on that app registration, in that
tenant. Two things are worth understanding up front:
-
It is about the value, not the date. If the secret were correct but past
its expiry, you would get
AADSTS7000222instead. Getting7000215means whatever string you sent simply is not a current secret on this app. - Nothing is broken in Azure. The app registration is fine, and the secret you created in the portal is fine. The string your application is sending just is not it.
AADSTS7000215 vs AADSTS7000222: which one do you have?
The two errors travel together. One is about a secret that ran out of time; the other is about a secret that was never right to begin with. Here is the difference at a glance:
| AADSTS7000215 | AADSTS7000222 | |
|---|---|---|
| Error message | “Invalid client secret provided” | “The provided client secret keys for app are expired” |
| What it means | The secret value is wrong — it matches no active secret on the app | The secret value was right, but it has passed its expiration date |
| Most common cause | The Secret ID was pasted instead of the Value | Nobody rotated the secret before its expiry date |
| Fix | Create a new secret, copy the Value, update the config | Create a new secret, update every place the old one was used |
| Full guide | This article | Fix AADSTS7000222 |
A useful way to remember it: 7000222 is a calendar problem,
7000215 is a copy-paste problem. The first one happens to you.
The second one you usually do to yourself — in a hurry, while fixing the first
one.
The classic mistake: Secret ID instead of Value
When you create a client secret, the Certificates & secrets blade shows two columns that both look like credentials: Value and Secret ID. The Secret ID is just a database identifier — a GUID that is always visible and completely useless for authentication. The Value is the actual credential, and it is displayed exactly once. The moment you navigate away, Azure masks it forever.
So when someone comes back to the page later to grab “the secret”, the only thing left to copy is the Secret ID. Which is precisely what people copy. The value they need was on screen for one visit, weeks ago, and nobody saved it — or it went into a notebook that has since been closed.
The shape gives it away. A Secret ID is always a GUID. A secret value is a ~40-character
random string with mixed case, digits, and punctuation. If the credential in your
config matches xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, you have the ID,
and no amount of redeploying will make it work.
Every other way to earn a 7000215
If your secret does not look like a GUID and you are still getting the error, work down this list. It is ordered by how often each one turns out to be the answer:
1. Whitespace and invisible characters
A trailing newline picked up while copying from a terminal, quotes accidentally baked
into an environment variable ("abc~123" instead of abc~123),
or a stray space at either end. Entra ID compares the value exactly; one invisible
character is enough.
2. The secret was not form-encoded
If you build the token request by hand — raw HTTP against
/oauth2/v2.0/token — the secret must be URL-encoded in the request
body, and secret values regularly contain characters that need it. If you use MSAL or
an Azure SDK, this is handled for you, which is one of several good reasons to use
them.
3. Right secret, wrong app — or wrong tenant
The client_id and client_secret in your config came from two
different app registrations, or from the right app in the wrong tenant. This happens
more than anyone admits in environments with separate dev, test, and prod tenants:
the secret is perfectly valid, just not for the app you are authenticating as.
4. The app is still reading the old value
You updated Key Vault, but the application caches secrets at startup and was never restarted. Or the deployment slot you are testing has its own application settings. Or the CI/CD variable group was updated but the pipeline that deploys the config has not run yet. The new value exists; it is just not the one in memory.
5. The secret is seconds old
Rarely, a freshly created secret takes a few minutes to propagate. If you created the secret, updated the config, and tested within the same minute, get a coffee and try once more before tearing anything else apart.
How to fix it
Do not spend time trying to recover the old value — you cannot. The Graph API does not return secret values after creation, and neither does the portal. The fix is always forward:
- Open the Microsoft Entra admin center → App registrations → [your app] → Certificates & secrets, and create a new client secret.
- Copy the Value column immediately — not the Secret ID. This is the only time it is shown.
- Update every place the secret is used: app settings, Key Vault, service connections, partner systems. The full checklist of places a secret hides is in our AADSTS7000222 guide, and it applies here unchanged.
- Restart or redeploy the affected service so it picks up the new value.
- Delete the secret that caused the confusion, so nobody trips over it again.
Verify the secret directly, outside your app
When the error persists, the fastest way to find out whether the problem is the secret or your application is to take the application out of the equation. Request a token directly:
$tenantId = "<your-tenant-id>"
$body = @{
client_id = "<your-app-id>"
client_secret = "<the-new-secret-value>"
scope = "https://graph.microsoft.com/.default"
grant_type = "client_credentials"
}
Invoke-RestMethod -Method Post `
-Uri "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" `
-Body $body
If this returns an access_token, the secret is good and the problem is
in your application's configuration — go back to cause #4. If it returns
7000215 again, the value you are holding is wrong — go back to
step 1 and watch which column you copy.
Why this error loves rotation day
Almost nobody gets 7000215 on a quiet afternoon. It shows up during
rotations — and rotations, in most teams, happen under pressure, because the
trigger is a secret that has already expired and is already breaking
production. A rushed rotation at 2 a.m., in an unfamiliar blade, with an incident
channel demanding updates, is exactly the environment where someone copies the wrong
column.
The durable fix is not “be more careful”. It is removing the time pressure. If you know about every expiration weeks in advance, rotation becomes a planned task done calmly during business hours, with time to double-check which column you copied — instead of a race against an outage.
And if you migrate workloads to managed identities or Workload Identity Federation
where you can, there is no secret to copy at all — which is the only rotation
procedure that has never produced a 7000215.
FAQ
7000215 means the secret value is wrong — a typo, the Secret ID instead of the Value, whitespace, or the wrong app/tenant. 7000222 means the value was right but the secret has expired. See our full AADSTS7000222 guide for the expired case.
~. If your "secret" looks like a GUID, it is the ID.
AADSTS7000222, not 7000215. If you are seeing 7000215, the value itself is wrong — though the two often appear in the same incident, when a rushed rotation after an expiry copies the wrong value.
Token Watch